Trabajo elaborado para la asignatura “Programación y manejo de datos en la era del Big Data” de la Universitat de València durante el curso 2021-2022. El repo del trabajo está aquí.

La página web de la asignatura y los trabajos de mis compañeros pueden verse aquí.


Librería de paquetes

Campeón del mundo

# aqui irá foto y cosillas del campeon de este finde

Historia de la F1

LOGOS DE LA FORMULA 1

Logo de 1985 a 1986

Logo de 1985 a 1986

Logo de 1987 a 1993

Logo de 1987 a 1993

Logo de 1994 a 2017

Logo de 1994 a 2017

Logo Actual

LOGO desde 2018 hasta la actualidad

Coches

datos Protagonistas

#---PREPARACION DE LOS DATOS

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
#str(resultados)
#str(pilotos)
#pilotos[, c(1)] <- sapply(pilotos[, c(1)], as.numeric)
#resultados[, c(3,6,9)] <- sapply(resultados[, c(3,6,9)], as.numeric)

#----------------------------------------------------------------------------------
#numero de carreras que ha corrido cada piloto

#explicacion de lo que hago, no se porque la variable sumatorio no la detecta como numerica aunque la pase a numerica, por tanto al ordenar con slice max no funciona, lo que he hecho es usar la funcion arrange, que ordena de menor a mayor, pero como queremos los que mas carreras han corrido, no me sirve de menor a mayor, por tanto he multiplicado la variable del sumatorio por -1, he usado arrange para que los que más carreras tienen salgan primero, y luego he vuelto a multiplicar por -1. luego he cogido mayores de 202 carreras, que son los 20 que más tienen, porque si hago slice se descuadra y te devuelve el df del principio

n_carreras <- resultados %>% group_by(driverId) %>% mutate(numero_carreras = sum(n())) %>% distinct(numero_carreras) %>% arrange(desc(numero_carreras)) #mutate(numero_carreras_final = numero_carreras*-1)

n_carreras_nom <- full_join(n_carreras, pilotos, c ("driverId" = "driverId")) %>% select(driverId, driverRef, numero_carreras)  %>%  filter(numero_carreras >= 202 ) #los 20 qque mas carreras tienen (no funciona usar slice_max)

#--------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# numero de victorias por piloto
victorias <- resultados %>% filter(position == "1") %>% group_by(driverId) %>% mutate(n_victorias = sum(n())) %>% distinct(n_victorias) %>% arrange(desc(n_victorias))#mutate(n_victorias_final = n_victorias*-1)

#aqui fusiono con el df de pilotos para que aparezca el nombre y no sólo el ID del piloto en cuestion, y hago lo mismo que en el apartado de arriba para ordenar
victorias_con_nombre <- full_join(victorias, pilotos, c ("driverId" = "driverId")) %>% select(driverId, nationality, driverRef, n_victorias)  #los 10 con mas victorias, tmp funciona slice_max
mas_victorias <- victorias_con_nombre %>%  filter(n_victorias >= 25 ) 




#-------------------------------------------------

#resultado medio

resultados[, c(7)] <- sapply(resultados[, c(7)], as.numeric)
resultados[is.na(resultados)] <- 25 

resultado_medio <-  full_join(pilotos, resultados,  c ("driverId" = "driverId")) %>% select(driverId, driverRef, position) %>% group_by(driverId) %>% mutate(result_medio = mean(position)) %>% distinct (driverId, driverRef, result_medio) %>% arrange(result_medio)

#resultado medio en clasificacion
resultado_medio_clas <-  full_join(pilotos, resultados,  c ("driverId" = "driverId")) %>% select(driverId, driverRef, grid) %>% group_by(driverId) %>% mutate(result_medio_clas = mean(grid)) %>% distinct (driverId, driverRef, result_medio_clas)  %>% filter(result_medio_clas > 0) %>% arrange(result_medio_clas)  


#numero de vueltas liderando


#puntos por carrera (puntos/carrera)

puntos_x_carrera <-  full_join(pilotos, resultados,  c ("driverId" = "driverId")) %>% select(driverId, driverRef, points) %>% full_join(., n_carreras,  c ("driverId" = "driverId")) %>% group_by(driverId) %>% mutate(total_puntos = sum(points)) %>% distinct(driverId, driverRef, numero_carreras, total_puntos) %>% mutate(media_puntos = total_puntos/numero_carreras) %>% arrange(desc(media_puntos))

Grafico más victorias

#se necesita "mas_victorias"

#hay que darle formato y mirar lo de animarlo por fecha


gg_mas_victorias <- ggplot(mas_victorias, aes(x = reorder(driverRef, n_victorias), y = n_victorias )) + geom_bar(stat = "identity") + labs(x = "Piloto" , y = "Número de victorias")
gg_mas_victorias
#trabajo --> darle formato chulo, ya veremos este puente si le podemos meter dinámico o que

Parrilla de pilotos 2021 tabla

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
carreras <- rio::import(file = "./datos/races.csv")
library(stringr)


pilotos_2021 <- full_join(carreras, resultados, c("raceId" = "raceId") ) %>% 
  full_join(.,pilotos, c("driverId"="driverId")) %>% 
  filter(year=="2021") %>% 
  select(forename,surname, year) %>% distinct(forename,surname) %>% na.omit() %>% arrange(surname) %>% str_replace_all(., "é", "é") %>% str_replace_all(., "ä", "ä") %>% str_replace_all(., "ö", "ö")

nombres_normales <- c("Alonso", "Bottas", "Gasly", "Giovinazzi", "Hamilton", "Latifi", "Leclerc", "Mazepin", "Norris", "Ocon", "Pérez", "Räikkönen", "Ricciardo", "Russell", "Sainz", "Schumacher", "Stroll", "Tsunoda", "Verstappen", "Vettel")

pilotos_2021 <-  full_join(carreras, resultados, c("raceId" = "raceId") ) %>% 
  full_join(.,pilotos, c("driverId"="driverId")) %>% 
  filter(year=="2021") %>% 
  select(forename,surname, year) %>% distinct(forename,surname) %>% na.omit() %>% arrange(surname) %>% add_column(nombres_normales)  
 

# Pérez
# Räikkönen
fotos_pil_2021 <- c("./imagenes/pilotos/alonso.png", "./imagenes/pilotos/bottas.png", "./imagenes/pilotos/gasly.png", "./imagenes/pilotos/giovinazzi.jpg", "./imagenes/pilotos/hamilton.png", "./imagenes/pilotos/latifi.png", "./imagenes/pilotos/leclerc.png", "./imagenes/pilotos/mazepin.png", "./imagenes/pilotos/norris.png", "./imagenes/pilotos/ocon.jpg", "./imagenes/pilotos/perez.png", "./imagenes/pilotos/raikkonen.png", "./imagenes/pilotos/ricciardo.png", "./imagenes/pilotos/russell.png", "./imagenes/pilotos/sainz.png", "./imagenes/pilotos/mick.png", "./imagenes/pilotos/stroll.png", "./imagenes/pilotos/tsunoda.png", "./imagenes/pilotos/verstappen.jpg", "./imagenes/pilotos/vettel.png")

fotos_pais_2021 <- c("./imagenes/paises/espanya.png", "./imagenes/paises/finlandia.png", "./imagenes/paises/francia.png", "./imagenes/paises/italia.png","./imagenes/paises/uk.png", "./imagenes/paises/canada.png","./imagenes/paises/monaco.png", "./imagenes/paises/rusia.png","./imagenes/paises/uk.png", "./imagenes/paises/francia.png","./imagenes/paises/mexico.png", "./imagenes/paises/finlandia.png","./imagenes/paises/australia.png", "./imagenes/paises/uk.png","./imagenes/paises/espanya.png", "./imagenes/paises/alemania.png","./imagenes/paises/canada.png", "./imagenes/paises/japon.png","./imagenes/paises/holanda.png", "./imagenes/paises/alemania.png")

fotos_esc_2021 <- c("./imagenes/escuderias/alpine.png","./imagenes/escuderias/mercedes.png","./imagenes/escuderias/alphatauri.png", "./imagenes/escuderias/alfaromeo.jpg","./imagenes/escuderias/mercedes.png", "./imagenes/escuderias/williams.png","./imagenes/escuderias/ferrari.png", "./imagenes/escuderias/haas.png","./imagenes/escuderias/mclaren.png", "./imagenes/escuderias/alpine.png","./imagenes/escuderias/redbull.png", "./imagenes/escuderias/alfaromeo.jpg","./imagenes/escuderias/mclaren.png", "./imagenes/escuderias/williams.png","./imagenes/escuderias/ferrari.png", "./imagenes/escuderias/haas.png","./imagenes/escuderias/aston.png", "./imagenes/escuderias/alphatauri.png","./imagenes/escuderias/redbull.png", "./imagenes/escuderias/aston.png")

pilotos_2021 <- pilotos_2021 %>%
  add_column(fotos_pil_2021, fotos_pais_2021, fotos_esc_2021) %>% select(nombres_normales, fotos_pil_2021, fotos_pais_2021, fotos_esc_2021)

library(gt)
mundial_2021 <- pilotos_2021 %>% gt() %>% text_transform( locations = cells_body(columns = c(fotos_pil_2021)), fn = function(x) {gt::local_image(x, height = 80)}) %>% text_transform( locations = cells_body(columns = c(fotos_pais_2021)), fn = function(x) {gt::local_image(x, height = 80)}) %>% text_transform( locations = cells_body(columns = c(fotos_esc_2021)), fn = function(x) {gt::local_image(x, height = 80)}) %>% tab_header(title = md("**Pilotos 2021**"), subtitle = md("Parrilla")) %>%   cols_label(
    nombres_normales = html(""),
    fotos_pil_2021 = html(""),
    fotos_pais_2021 = html(""),
    fotos_esc_2021 = html("")) %>%  
  tab_options(table.background.color = "gray13",   table.font.color.light = "cyan") %>% 
  cols_align(align = "center",
  columns = everything())


mundial_2021
Pilotos 2021
Parrilla
Alonso
Bottas
Gasly
Giovinazzi
Hamilton
Latifi
Leclerc
Mazepin
Norris
Ocon
Pérez
Räikkönen
Ricciardo
Russell
Sainz
Schumacher
Stroll
Tsunoda
Verstappen
Vettel

Españoles por la F1

#--------------------------------------------------------------------------------------
#pilotos españoles

pilotos <- rio::import(file = "./datos/drivers.csv")

pilotos_esp <- pilotos %>% filter(nationality == "Spanish") %>% select(driverId, driverRef, nationality) 


#mas victorias de pilotos españoles
mas_victorias_esp <- full_join(victorias_con_nombre, pilotos, c ("driverId" = "driverId")) %>% filter(nationality.x == "Spanish") %>%  select(driverId, driverRef.x, n_victorias, nationality.x) 


#-------------------------------------------------------------------------------------------

Escuderías campeonas

Por tamaño

#datos de escuderias pa quien quiera hacer algo
#escuderias <- rio::import(file = "./datos/constructors.csv")
#escuderias2 <- rio::import(file = "./datos/constructor_standings.csv")
#result_escuderias <- rio::import(file = "./datos/constructor_results.csv")

#pilotos <- rio::import(file = "./datos/drivers.csv")
#resultados <- rio::import(file = "./datos/results.csv")
#carreras <- rio::import(file = "./datos/races.csv")
#escuderiasesp <- escuderias %>% filter(nationality == "Spanish") #escuderias españolas

#campeones_esc <- full_join(pilotos, resultados, c("driverId" = "driverId")) %>% full_join(., carreras, c("raceId" = "raceId")) %>% select(driverId, driverRef, nationality, constructorId, points, year, round) %>% full_join(., escuderias, c("constructorId" = "constructorId")) %>% select(driverId, driverRef, nationality.x, constructorId, points, year, name, round) %>%  group_by(year, driverRef) %>%  mutate(puntos_totales = cumsum(points)) %>% ungroup() %>% group_by(year) %>% slice_max(puntos_totales, n=1) %>% select(name, driverRef) %>% group_by(name, driverRef) %>% mutate(total_camp = sum( NN = n())) %>% arrange(name) 


#campeones_esc <- campeones_esc[!(campeones_esc$driverRef == 'max_verstappen'),] 

#library(treemap)
#library(d3treeR)


# basic treemap
#gg_esc_campeones <- treemap(campeones_esc,
            #index=c("name","driverRef"),
            #vSize="total_camp",
            #type="index",
            #vColor = "name",
            #fontsize.labels=c(25,17),
            #bg.labels=c("transparent"),
            #palette = "Set2",
            #align.labels=list(
              #c("center", "center"), 
              #c("center", "bottom")),
            #title = "Escuderías con más campeones",
            #title.legend = "Escuderías")   
inter_camp <- d3tree2(gg_esc_campeones ,  rootname = "Escuderías y Campeones")
inter_camp

En valores absolutos

campeones_esc <- full_join(pilotos, resultados, c("driverId" = "driverId")) %>% full_join(., carreras, c("raceId" = "raceId")) %>% select(driverId, driverRef, nationality, constructorId, points, year, round) %>% full_join(., escuderias, c("constructorId" = "constructorId")) %>% select(driverId, driverRef, nationality.x, constructorId, points, year, name, round) %>%  group_by(year, driverRef) %>%  mutate(puntos_totales = cumsum(points)) %>% ungroup() %>% group_by(year) %>% slice_max(puntos_totales, n=1) %>% ungroup() %>% count(name) %>% arrange(desc(n))


ggplot(campeones_esc, aes(x = reorder(name,n),y = n)) + geom_bar(stat = "identity") + coord_flip()

Alonso (el nano)

#alonso vs compañeros de equipo

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
escuderias <- rio::import(file = "./datos/constructors.csv")
carreras <- rio::import(file = "./datos/races.csv")

alovsall <- full_join(pilotos, resultados, c ("driverId" = "driverId")) %>%  select(driverRef, resultId, raceId, constructorId, position, points) %>% full_join(., escuderias, c ("constructorId" = "constructorId")) %>% select(driverRef, resultId, raceId, constructorId, position, position, points, name) %>% full_join(., carreras, c ("raceId" = "raceId")) %>% select(driverRef, resultId, raceId, constructorId, position, position, points, name.x, year, round)

#alo_vs_marques <- alovsall %>% filter(year == 2001, driverRef %in% c("alonso", "marques"), round <= 14)

alo_vs_trulli <- alovsall %>% filter(year %in% c(2003, 2004), driverRef %in% c("alonso", "trulli")) %>% slice(1:15, 17:67) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_fisichella <- alovsall %>% filter(year %in% c(2005, 2006), driverRef %in% c("alonso", "fisichella"))  %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_hamilton <- alovsall %>% filter(year %in% c(2007) ,driverRef %in% c("alonso", "hamilton"))  %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_piquet <- alovsall %>% filter(year %in% c(2008, 2009), driverRef %in% c("alonso", "piquet_jr")) %>% slice(1:28, 36:63) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

#alo_vs_grosjean <- alovsall %>% filter(year == 2009, driverRef %in% c("alonso", "grosjean"), round >= 11)

alo_vs_massa <- alovsall %>% filter(year %in% c(2010, 2011, 2013), driverRef %in% c("alonso", "massa")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_raikkonen <- alovsall %>% filter(year == 2014, driverRef %in% c("alonso", "raikkonen")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_button <- alovsall %>% filter(year %in% c(2015, 2016), driverRef %in% c("alonso", "button")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_vandoorne <- alovsall %>% filter(year %in% c(2017, 2018), driverRef %in% c("alonso", "vandoorne")) %>% slice(1:45, 47:81) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points))%>% ungroup() 

alo_vs_ocon <- alovsall %>% filter(year == 2021, driverRef %in% c("alonso", "ocon")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

ALO_VS_ALL <- full_join(alo_vs_trulli, alo_vs_fisichella, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round" , "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_hamilton, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_piquet, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_massa, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados"))  %>% 
  full_join(., alo_vs_raikkonen, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_button, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_vandoorne, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_ocon, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados"))

objetos_no_borrar <- c("ALO_VS_ALL", "n_carreras_nom", "victorias_con_nombre")
rm(list = ls()[!ls() %in% objetos_no_borrar])


gc() #instruccion para que cargue el grafico, al ser tan complejo da error de no sé qué pero con esto funciona
#>           used (Mb) gc trigger  (Mb) max used  (Mb)
#> Ncells 1752119 93.6    3337494 178.3  3337494 178.3
#> Vcells 4252827 32.5   14786712 112.9 14748682 112.6
ggalo_vs_all <- ggplot(data = ALO_VS_ALL, aes(round, puntos_acumulados, color = driverRef)) +
  geom_line() +
  geom_point() + 
  labs(title = "Alonso contra el mundo",
       subtitle = "le das un carton con ruedas y aún te saca puntos",
       y = "Puntos", x = "") + facet_wrap( ~ year) + transition_reveal(round)

#ggalo_vs_all

Campeones del mundo

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
escuderias <- rio::import(file = "./datos/constructors.csv")
carreras <- rio::import(file = "./datos/races.csv")



campeones <- full_join(pilotos, resultados, c("driverId" = "driverId")) %>% full_join(., carreras, c("raceId" = "raceId")) %>% select(driverId, driverRef, nationality, constructorId, points, year, round) %>% full_join(., escuderias, c("constructorId" = "constructorId")) %>% select(driverId, driverRef, nationality.x, constructorId, points, year, name, round) %>%  group_by(year, driverRef) %>%  mutate(puntos_totales = cumsum(points)) %>% ungroup() %>% group_by(year) %>% slice_max(puntos_totales, n=1) %>% ungroup() %>% group_by(driverRef)%>% mutate(total_campeonatos = sum(NN = n())) %>% distinct(driverRef, nationality.x, total_campeonatos) %>% arrange(nationality.x, total_campeonatos)
  
campeones <- campeones[!(campeones$driverRef == 'max verstappen'),]
id <- rownames(campeones)
campeones <- cbind(id=id, campeones)
campeones[, c(1)] <- sapply(campeones[, c(1)], as.numeric)




label_campeones <- campeones
number_of_bar <- nrow(label_campeones)

angle <- 90 - 360 * (label_campeones$id-0.5) /number_of_bar     # I substract 0.5 because the letter must have the angle of the center of the bars. Not extreme right(1) or extreme left (0)
label_campeones$hjust <- ifelse( angle < -90, 1, 0)
label_campeones$angle <- ifelse(angle < -90, angle+180, angle)



base_campeones <- campeones %>% 
  group_by(nationality.x) %>% 
  summarise(start=min(id), end=max(id)) %>% 
  rowwise() %>% 
  mutate(title=mean(c(start, end)))

grid_campeones <- base_campeones
grid_campeones$end <- grid_campeones$end[ c( nrow(grid_campeones), 1:nrow(grid_campeones)-1)] + 1
grid_campeones$start <- grid_campeones$start - 1
grid_campeones <- grid_campeones[-1,]

p <- ggplot(campeones, aes(x=as.factor(year), y=total_campeonatos, fill=nationality.x, color = nationality.x)) + geom_bar(aes(x=as.factor(id), y=total_campeonatos, fill=nationality.x), stat="identity", alpha=0.5) +
  
  geom_segment(data=grid_campeones, aes(x = 0, y = 8, xend = 32, yend = 8), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 0, y = 6, xend = 32, yend = 6), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 0, y = 4, xend = 32, yend = 4), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 0, y = 2, xend = 32, yend = 2), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  
  annotate("text", x = rep(max(campeones$id),4), y = c(2, 4, 6, 8), label = c("2", "4", "6", "8") , color="white", size=3 , angle=0, fontface="bold", hjust=1) +
  
   geom_bar(aes(x=as.factor(id), y=total_campeonatos, fill=nationality.x), stat="identity", alpha=0.5) +
  ylim(-10,21) +
  theme_minimal() +
  theme(
    legend.position = "none",
    axis.text = element_blank(),
    axis.title = element_blank(),
    panel.grid = element_blank(),
    plot.margin = unit(rep(-1,4), "cm") ) +
  coord_polar() + 
  geom_text(data=label_campeones, aes(x=id, y=10, label=driverRef, hjust=hjust), color="white", fontface="bold",alpha=0.6, size=3.5, angle= label_campeones$angle, inherit.aes = FALSE ) +

  geom_segment(data=grid_campeones, aes(x = 0.70, y = -1, xend = 2.45, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE )  +
  geom_segment(data=grid_campeones, aes(x = 2.6, y = -1, xend = 3.55, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 3.65, y = -1, xend = 5.45, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 5.55, y = -1, xend = 7.35, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 7.5, y = -1, xend = 10.50, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 10.7, y = -1, xend = 19.20, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 19.4, y = -1, xend = 20.3, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 20.45, y = -1, xend = 23.4, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + 
  geom_segment(data=grid_campeones, aes(x = 23.65, y = -1, xend = 24.35, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + 
  geom_segment(data=grid_campeones, aes(x = 24.60, y = -1, xend = 27, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 27.2, y = -1, xend = 29.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 29.7, y = -1, xend = 30.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + 
  geom_segment(data=grid_campeones, aes(x = 30.7, y = -1, xend = 31.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 31.7, y = -1, xend = 32.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 32.7, y = -1, xend = 33.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + theme(legend.text = element_text(colour = "white"),
    legend.title = element_text( colour = "white"), 
     legend.background = element_rect(fill = "gray13", colour = "gray13"),
    legend.key = element_rect(fill = "gray13"),
    legend.position = "right",
    panel.background = element_rect(fill = "gray13" , colour = "gray13"),
    plot.background = element_rect(fill = "gray13" , colour = "gray13"))
  


p

templos y tiempos (temp 2021) globo interactivo

carreras <- rio::import(file = "./datos/races.csv")
circuitos <- rio::import(file = "./datos/circuits.csv")

carreras_21 <- full_join(carreras,circuitos, c("circuitId" = "circuitId")) %>%
  filter(year=="2020") %>%
  select(round, name.x, name.y, date, location,country, lat, lng, alt) %>%
  arrange(round) %>% 
  mutate(round2 = round) 

carreras_21_v2 <- carreras_21[, c(1, 4, 10, 2, 3, 5, 6, 7, 8, 9)]
carreras_21_v2 <- carreras_21_v2%>%  unite(. ,variables, c(1, 5, 7), sep = "; ")

#pruebas para mapas, no ejecutar de momento
#library(widgetframe)
#library(leaflet)
#l <- leaflet() %>% setView(lat = 45.61560, lng = 9.281110, zoom=1)
#frameWidget(l) 

#mapaCiudadyPueblomayorinciAcu <- leaflet() %>%
 # setView(lng = -0.243591, lat = 38.821, zoom = 7) %>% 
  #addMarkers(lng = -0.243591, lat = 38.821 , popup = "Vall de Gallinera")%>%
  #setView(lng = -0.418598, lat = 40.2011, zoom = 7) %>% 
  #addMarkers(lng = -0.418598, lat = 40.2011 , popup = "Villahermosa del rio") %>% addTiles()
#mapaCiudadyPueblomayorinciAcu

#MAPA DEL MUNDO DE LA OSTIA NO TOCAR, pongo como comentario para que no tarde tanto al knitear


globo_circ <-create_globe() %>% globe_pov(45.61560, 9.281110) %>% globe_bars(coords(lat, lng, label  = variables, color = round2), data = carreras_21_v2)  %>% scale_bars_color()
#globo_circ

objetos_no_borrar <- c("victorias_con_nombre", "n_carreras_nom", "mas_victorias")
rm(list = ls()[!ls() %in% objetos_no_borrar])
circuitos <- rio::import(file = "./datos/circuits.csv")
tiempos <- rio::import(file = "./datos/lap_times.csv")
carreras <- rio::import(file = "./datos/races.csv")
pilotos <- rio::import(file = "./datos/drivers.csv")

circuitos_gp <- full_join(carreras, circuitos, c("circuitId" = "circuitId")) #asocio las carreras a su circuito
tiemposvuelta_x_carrera <- full_join(circuitos_gp, tiempos, c ("raceId" = "raceId")) #tiempo de las vueltas por cada carrera

tiemposvuelta_x_carrera <- full_join(tiemposvuelta_x_carrera, pilotos, c ("driverId" = "driverId")) %>%  select(circuitId, name.y, driverId, driverRef, time.y, lap,position, year, country) #fusiono con el df de pilotos para asociar cada vuelta al nombre del piloto que la hizo


#calculo el record de cada circuito, filtrando el minimo de los tiempos en cada circuito
record_de_circuito <- tiemposvuelta_x_carrera %>% group_by(name.y) %>% slice_min(time.y, n=1)

#numero de records de circuito que tiene cada piloto
record_x_piloto <- record_de_circuito %>% group_by(driverId) %>% mutate(numero_records = sum(n())) %>% select(driverId, driverRef, numero_records) %>% distinct(driverRef, numero_records) %>% arrange(desc(numero_records))


# meter mapa del mundo con la ubicacion de los circuitos en la temporada 2021
#------------------------------------------------------------

objetos_no_borrar <- c("victorias_con_nombre", "n_carreras_nom", "mas_victorias")
rm(list = ls()[!ls() %in% objetos_no_borrar])

Capítulo oscuro del deporte

#creo df de muertes de formula 1
muertesf1 <- data.frame(
  "orden" = 1:42,
  "driverRef" = c("Chet Miller", "Carl Scaraborough", "Onofre Marimon", "Manny Ayulo", "Bill Vukovich", "Alberto Ascari","Eugenio Castellotti", "Keith Andrews", "Pat O'Connor", "Luigi Musso", "Peter Collins", "Stuart Lewis-Evans", "Jerry Unser", "Bob Cortner", "Ivor Bueb", "Chris Bristow", "Alan Stacey", "Giulio Cabianca", "Wolfgang von Trips", "Carel Godin de Beaufort", "John Taylor", "Lorenzo Bandini", "Bob Anderson", "Jo Schlesser", "Gerhard Mitter", "Piers Courage", "Jochen Rindt", "Jo Siffert", "Roger Williamson", "François Cevert", "Peter Revson", "Helmuth Koinigg", "Mark Donohue", "Tom Pryce", "Ronnie Peterson", "Patrick Depailler", "Gilles Villeneuve", "Riccardo Paletti", "Elio de Angelis", "Roland Ratzenberger", "Ayrton Senna", "Jules Bianchi"),
  "nationality" = c("American", "American", "Argentine", "American", "American", "Italian","Italian", "American", "American", "Italian", "British", "British", "American", "American", "British", "British", "British", "Italian", "German", "Dutch", "British", "Italian" , "British", "French", "German", "British", "Austrian", "Swiss", "British", "French", "American", "Austrian", "American", "British", "Swedish", "French", "Canadian", "Italian", "Italian", "Austrian", "Brazilian", "French"),
  "fecha_muerte" = c(1953, 1953, 1954, 1955, 1955, 1955, 1957, 1957, 1958,1958,1958,1958,1959,1959,1959,1960, 1960,1961,1961,1964,1966, 1967, 1967,1968,1969, 1970,1970,1971,1973,1973,1974,1974,1975,1977,1978,1980,1982,1982,1986,1994,1994,2014))
#no pongo las comillas en los años para que se creen directamente como observaciones numericas

#creo un df con todos los años para luego fusionarlo, ya que no hay muertes todos los años 
anyos <- data.frame(
  "orden" = 1:71,
  "año" = c(1950:2020))

#sumatorio de las muertes por año
muertes_anyo <- muertesf1 %>% group_by(fecha_muerte) %>% mutate(muertesxanyo = sum(n())) %>% distinct(fecha_muerte, muertesxanyo) 

#fusiono los 2 dfs para que tenga en cuenta los años donde no hay muertes
muertesf1_final <- full_join(muertes_anyo, anyos, c("fecha_muerte" = "año")) %>% select(fecha_muerte,muertesxanyo) %>% arrange(fecha_muerte)

#convierto los N/A en 0, es decir, cuando no hay observaciones, ha habido 0 muertes
muertesf1_final[is.na(muertesf1_final)] <- 0

#grafico de las muertes por cada año + la tendencia negativa ea lo largo de la historia
gg_muertes <- ggplot(muertesf1_final, aes(x = fecha_muerte, y = muertesxanyo )) +  geom_bar(stat = "identity", fill = "white", colour = "white") + geom_smooth(colour = "cyan", se = FALSE) + labs(x = "Año" , y = "Número de muertes")  + theme(axis.line = element_line(colour = "white"),
    axis.ticks = element_line(colour = "white"),
    panel.grid.major = element_line(colour = "gray13"),
    panel.grid.minor = element_line(colour = "gray13"),
    axis.title = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    plot.title = element_text(colour = "white"),
    panel.background = element_rect(fill = "gray12",
        colour = "white"), plot.background = element_rect(fill = "gray13")) +labs(colour = "white") + theme(panel.grid.major = element_line(colour = "gray38",
    linetype = "dotted"), panel.grid.minor = element_line(colour = NA),
    plot.title = element_text(size = 25,
        hjust = 0.5)) +labs(title = "Accidentes mortales por año") + geom_text(data = data.frame(x = 2004.10522642875, y = 0.237450516942241, 
    label = "Tendencia negativa"), mapping = aes(x = x, y = y, 
    label = label), colour = "cyan", inherit.aes = FALSE, size = 3)

ggplotly(gg_muertes)

1. Introducción

Tenemos pensado elaborar el trabajo en equipo sobre Formula 1, una competición de la que somos muy aficionados, entre otras cosas por la importancia que tienen los datos a la hora de formalizar las estrategias en la competición.

Remando a contracorriente

#mas posiciones remontadas en una carrera gran premio

tiempos <- rio::import(file = "./datos/lap_times.csv")
carreras <- rio::import(file = "./datos/races.csv")
resultados <- rio::import(file = "./datos/results.csv")
circuitos <- rio::import(file = "./datos/circuits.csv")
pilotos <- rio::import(file = "./datos/drivers.csv")

resultados[, c(6,9)] <- sapply(resultados[, c(6,9)], as.numeric) #transformo variables grid y positionOrder en numerico
str(resultados) # para comprobarlo
#> 'data.frame':    25140 obs. of  18 variables:
#>  $ resultId       : int  1 2 3 4 5 6 7 8 9 10 ...
#>  $ raceId         : int  18 18 18 18 18 18 18 18 18 18 ...
#>  $ driverId       : int  1 2 3 4 5 6 7 8 9 10 ...
#>  $ constructorId  : int  1 2 3 4 1 3 5 6 2 7 ...
#>  $ number         : chr  "22" "3" "7" "5" ...
#>  $ grid           : num  1 5 7 11 3 13 17 15 2 18 ...
#>  $ position       : chr  "1" "2" "3" "4" ...
#>  $ positionText   : chr  "1" "2" "3" "4" ...
#>  $ positionOrder  : num  1 2 3 4 5 6 7 8 9 10 ...
#>  $ points         : num  10 8 6 5 4 3 2 1 0 0 ...
#>  $ laps           : int  58 58 58 58 58 57 55 53 47 43 ...
#>  $ time           : chr  "1:34:50.616" "+5.478" "+8.163" "+17.181" ...
#>  $ milliseconds   : chr  "5690616" "5696094" "5698779" "5707797" ...
#>  $ fastestLap     : chr  "39" "41" "41" "58" ...
#>  $ rank           : chr  "2" "3" "5" "7" ...
#>  $ fastestLapTime : chr  "1:27.452" "1:27.739" "1:28.090" "1:28.603" ...
#>  $ fastestLapSpeed: chr  "218.300" "217.586" "216.719" "215.464" ...
#>  $ statusId       : int  1 1 1 1 1 11 5 5 4 3 ...
#mayores remontadas de la historia, se resta posicion de salida - posicion final
puestos_remontados <- resultados %>% mutate(remontados = grid - positionOrder) %>% select(raceId, driverId, grid, positionOrder, remontados) 


#de toda la historia
circuitos_gp <- full_join(carreras, circuitos, c("circuitId" = "circuitId")) %>% select(circuitId, name.y, raceId, year)

ptos_remont_carrera <- inner_join(puestos_remontados, circuitos_gp)

puestos_remont_piloto <- full_join(pilotos, ptos_remont_carrera, c("driverId" = "driverId")) %>% slice_max(remontados, n=10) %>% select(driverId, driverRef,name.y,year, raceId, grid, positionOrder, remontados)

#------------------------------


# de la hisotoria reciente
circuitos_gp_recient <- full_join(carreras, circuitos, c("circuitId" = "circuitId")) %>% select(circuitId, name.y, raceId, year) %>% filter(year >= 1995)

ptos_remont_carrera_recient <- inner_join(puestos_remontados, circuitos_gp_recient)

puestos_remont_piloto_recient <- full_join(pilotos, ptos_remont_carrera_recient, c("driverId" = "driverId")) %>% slice_max(remontados, n=10) %>% select(driverId, driverRef, name.y, year,raceId, grid, positionOrder, remontados) %>% slice(1:4,6:8,10) %>% arrange(desc(remontados))

ggremontados <- ggplot(puestos_remont_piloto_recient, aes(x = reorder(driverRef, remontados), remontados)) + geom_bar(stat = "identity") + coord_flip() + labs(x = "Pilotos", y = "Nº de puestos remontados" )
ggremontados

objetos_no_borrar <- c("victorias_con_nombre", "n_carreras_nom", "mas_victorias")
rm(list = ls()[!ls() %in% objetos_no_borrar])

ALONSO vs HAMILTON

#se necesita tener cargado "n_carreras_nom", "victorias_con_nombre"
#1234
fotos_ALO_vs_HAM <- c("./imagenes/pilotos/alonso.png", "./imagenes/pilotos/hamilton.png")
fotos_esp_ing <- c("./imagenes/paises/espanya.png", "./imagenes/paises/uk.png")
n_carreras_alo_ham <- n_carreras_nom %>% filter(driverRef %in% c("alonso", "hamilton"))

n_victorias_alo_ham <- victorias_con_nombre %>% filter(driverRef %in% c("alonso", "hamilton"))

alo_vs_ham <- full_join(n_carreras_alo_ham, n_victorias_alo_ham, c("driverRef"= "driverRef")) %>% select( driverRef, numero_carreras, n_victorias) %>% add_column(fotos_esp_ing, fotos_ALO_vs_HAM) 

library(gt)
alo_vs_ham_tabla <- alo_vs_ham %>% gt() %>% text_transform( locations = cells_body(columns = c(fotos_esp_ing)), fn = function(x) {gt::local_image(x, height = 50)}) %>% text_transform( locations = cells_body(columns = c(fotos_ALO_vs_HAM)), fn = function(x) {gt::local_image(x, height = 100)}) %>% tab_header(title = md("**Alonso vs Hamilton**"), subtitle = md("Comparación")) %>%   cols_label(
    driverRef = html(""),
    numero_carreras = html("Nº carreras"),
    n_victorias = html("Nº victorias"),
    fotos_esp_ing = html("País"),
    fotos_ALO_vs_HAM = html("")) %>%  
  tab_options(table.background.color = "gray13",   table.font.color.light = "cyan") %>% 
  cols_align(align = "center",
  columns = everything())

alo_vs_ham_tabla
Alonso vs Hamilton
Comparación
Nº carreras Nº victorias País
alonso 323 32
hamilton 275 98

Audiencias

#audiencias


audiencias <- rio::import(file = "./datos/audienciasF1.csv")


gg_audiencias <- ggplot(audiencias, aes(x=year, y= numero_espectadores)) +
  geom_segment( aes(x=year, xend = year, y=0, yend= numero_espectadores , size = "1")) +
  geom_point( size=5, color="blue", fill=alpha("cyan", 8), alpha=0.7, shape=21, stroke=2) +  
  scale_x_continuous(
    breaks = seq(2004, 2020, 1),
    limits = c(2003, 2021)) + labs(x = "Año", y = "Numero de espectadores" )  + theme(panel.background = element_rect(fill = "gray13"),
    plot.background = element_rect(fill = "gray13")) + theme(axis.line = element_line(colour = "white"),
    panel.grid.major = element_line(colour = "gray20"),
    panel.grid.minor = element_line(colour = "gray20"),
    axis.text = element_text(colour = "white"),
    legend.position = "none") + theme(axis.title = element_text(colour = "white"),
    plot.title = element_text(colour = "white",
        hjust = 0.5)) +labs(title = "Evolución de la audiencia",
    colour = "white") + theme(axis.text.x = element_text(size = 4)) #+ transition_reveal(numero_espectadores)

ggplotly(gg_audiencias)

Presupuestos

#presupuestos

presupuestos <- read_excel("datos/presupuestos.xlsx")

gg_presup <- ggplot(presupuestos, aes(year, Presupuesto, color = Escuderia)) + 
  geom_point() + geom_line() + 
  labs(x = "Año", y = "Presupuesto en €" ) +
    scale_x_continuous(
    breaks = seq(2015, 2023, 1),
    limits = c(2014, 2024)) + 
  scale_y_continuous( breaks = seq(0, 700000000, 100000000),
    limits = c(0, 600000000))  + theme(axis.ticks = element_line(colour = "white"),
    panel.grid.major = element_line(colour = "white",
        linetype = "blank"), panel.grid.minor = element_line(colour = "white",
        linetype = "blank"), axis.title = element_text(size = 14,
        face = "bold", colour = "cyan", vjust = 0.75),
    axis.text = element_text(colour = "white"),
    plot.title = element_text(size = 16,
        face = "bold", colour = "cyan", hjust = 0.5,
        vjust = 0.75), legend.text = element_text(face = "bold",
        colour = "cyan"), legend.title = element_text(size = 13,
        face = "bold", colour = "cyan"),
    panel.background = element_rect(fill = "gray13",
        colour = "white"), plot.background = element_rect(fill = "gray13"),
    legend.key = element_rect(fill = "gray13"),
    legend.background = element_rect(fill = "gray13")) +labs(title = "PRESUPUESTO DE CADA EQUIPO POR TEMPORADA") + theme(panel.grid.major = element_line(colour = NA),
    panel.grid.minor = element_line(colour = NA),
    axis.title = element_text(size = 11),
    plot.title = element_text(size = 14),
    legend.text = element_text(size = 9),
    legend.title = element_text(size = 11),
    panel.background = element_rect(fill = "gray13",
        colour = NA), plot.background = element_rect(fill = "gray13",
        colour = NA)) + theme(legend.key = element_rect(fill = "gray13"),
    legend.background = element_rect(fill = "gray13")) + theme(axis.line = element_line(colour = "gray20",
    linetype = "solid"), panel.grid.major = element_line(colour = "gray15",
    linetype = "solid"))
 
ggplotly(gg_presup) #para que sea interactivo

mapa de coropletas de pilotos por pais (por terminar)

pilotos <- rio::import(file = "./datos/drivers.csv")

nacionalidad <- pilotos %>% group_by(nationality) %>% 
  mutate(numero_compatriotas = sum(n())) %>% 
  distinct(numero_compatriotas) %>% arrange(desc(numero_compatriotas)) %>% 
  mutate(country = case_when(nationality == "British" ~ "United Kingdom",
          nationality == "American" ~ "United States",
          nationality == "Italian" ~ 'Italy',
          nationality == "French" ~ 'France',
          nationality == "German" ~ 'Germany',
          nationality == "Brazilian" ~ 'Brazil',
          nationality == "Argentine" ~ 'Argentina',
          nationality == "Swiss" ~ 'Switzerland',
          nationality == "Belgian" ~ 'Belgium',
          nationality == "South African" ~ 'South Africa',
          nationality == "Japanese" ~ 'Japan',
          nationality == "Australian" ~ 'Australia',
          nationality == "Dutch" ~ 'Netherlands',
          nationality == "Spanish" ~ 'Spain',
          nationality == "Austrian" ~ 'Austria',
          nationality == "Canadian" ~ 'Canada',
          nationality == "Swedish" ~ 'Sweden',
          nationality == "Finnish" ~ 'Finland',
          nationality == "New Zealander" ~ 'New Zealand',
          nationality == "Mexican" ~ 'Mexico',
          nationality == "Irish" ~ 'Ireland',
          nationality == "Danish" ~ 'Denmark',
          nationality == "Portuguese" ~ 'Portugal',
          nationality == "Monegasque" ~ 'France',
          nationality == "Rhodesian" ~ 'Zimbabwe',
          nationality == "Uruguayan" ~ 'Uruguay',
          nationality == "Russian" ~ 'Russia',
          nationality == "Colombian" ~ 'Colombia',
          nationality == "Venezuelan" ~ 'Venezuela',
          nationality == "East German" ~ 'German',
          nationality == "Indian" ~ 'India',
          nationality == "Thai" ~ 'Thailand',
          nationality == "Polish" ~ 'Poland',
          nationality == "Hungarian" ~ 'Hungary',
          nationality == "Czech" ~ 'Czech Rep.',
          nationality == "Malaysian" ~ 'Malaysia',
          nationality == "Chilean" ~ 'Chile',
          nationality == "Liechtensteiner" ~ 'Switzerland',
          nationality == "American-Italian" ~ 'United States',
          nationality == "Argentine-Italian" ~ 'Argentina',
          nationality == "Indonesian" ~ 'Indonesia'))


library(tmap)
data(World)
world <- World; rm(World)

THE PLAN

2. Datos

Hemos encontrado en kaggle bastantes conjuntos de datos con los que poder trabajar, pero especialmente este, que posee gran variedad de datos en lo referente a pilotos, resultados, circuitos, tiempos, etc… Consideramos que para empezar a trabajar será suficiente, y en función de como vayamos dirigiendo el trabajo, buscaremos diferentes conjunto de datos con los que apoyarnos.

3. Trabajos en los que nos vamos a basar

Con los datos que hemos encontrado, existen una serie de códigos que ya trabajan con estos datos, especialmente este, que ha conseguido realizar análisis con este conjunto de datos y varias ilustraciones muy llamativas, por lo que podremos tomarlo como referencia durante el inicio del trabajo

“Nadie es más rápido que el nano”

library(magick)
coche1950 <- image_read("./imagenes/coches/1950.jpg") %>% image_scale(., "500") %>%  image_annotate(., "1950", size = 40, gravity = "southwest", color = "white")
coche1960 <- image_read("./imagenes/coches/1960.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1960", size = 40, gravity = "southwest", color = "white")
coche1970 <- image_read("./imagenes/coches/1970.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1970", size = 40, gravity = "southwest", color = "white")
coche1980 <- image_read("./imagenes/coches/1980.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1980", size = 40, gravity = "southwest", color = "white")
coche1990 <- image_read("./imagenes/coches/1990.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1990", size = 40, gravity = "southwest", color = "white")
coche2005 <- image_read("./imagenes/coches/2005.jpg") %>% image_scale(., "500")%>%  image_annotate(., "2005", size = 40, gravity = "southwest", color = "white")
coche2020 <- image_read("./imagenes/coches/2020.jpg") %>% image_scale(., "500")%>%  image_annotate(., "2020", size = 40, gravity = "southwest", color = "white")
coches <- c(coche1950, coche1960, coche1970, coche1980, coche1990, coche2005, coche2020)

image_animate(image_scale(coches), fps = 0.5)

LS0tDQp0aXRsZTogIkFsdCArIEZvcm11bGEgMSINCmF1dGhvcjogIkNheWV0YW5vIFJvbWVybyBNb250ZWFndWRvIChjYXJvbW9uM0BhbHVtbmkudXYuZXMpICBcblxuIEFsZWphbmRybyBHYXJjw61hIFNlZ2FycmEgKGFnYXJzZTRAYWx1bW5pLnV2LmVzKSAgXG4gXG4gQ2FybG9zIEdhcmPDrWEgQ2FzdGlsbGEgKGdhcmNhczhAYWx1bW5pLnV2LmVzKS4gXG5cbiBVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEiDQpkYXRlOiAiRGljaWVtYnJlIGRlIDIwMjEgKGFjdHVhbGl6YWRvIGVsIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWApIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgICNjc3M6ICIuL2Fzc2V0cy9teV9jc3NfZmlsZS5jc3MiDQogICAgdGhlbWU6IGRhcmtseQ0KICAgIGhpZ2hsaWdodDogdGFuZ28gDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzIA0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IHRydWUNCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBkZl9wcmludDoga2FibGUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCjwhLS0tIGNodW5rIHBhcmEgcXVlIGxhIGZ1ZW50ZSBzZWEgbGEgb2ZpY2lhbCBkZSBsYSBGb3JtdWxhIDEgLS0+DQpgYGB7Y3NzLCBlY2hvPUZBTFNFfSANCkBmb250LWZhY2Ugew0KICBmb250LWZhbWlseTogRjE7DQogIHNyYzogdXJsKGh0dHBzOi8vd3d3LmZvcm11bGExLmNvbS9ldGMvZGVzaWducy9mb20td2Vic2l0ZS9mb250cy9GMVJlZ3VsYXIvRm9ybXVsYTEtUmVndWxhci50dGYpOw0KfQ0KDQpzcGFuew0KICBmb250LWZhbWlseTogRjE7DQp9DQoNCmF7DQogIGZvbnQtZmFtaWx5OiBGMTsNCn0NCg0KLm5hdi1waWxscz5saS5hY3RpdmU+YTpmb2N1cyB7DQogICAgY29sb3I6ICNmZmZmZmY7DQogICAgYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5Ow0KfQ0KDQouY29udGFpbmVyLWZsdWlkLCAuY29udGFpbmVyLWZsdWlkIGgxIHsNCiAgICBmb250LWZhbWlseTogRjE7DQogICAgbGluZS1oZWlnaHQ6IDEuNzsNCn0NCg0KLmNvbnRhaW5lci1mbHVpZCBwIHsNCiAgICBmb250LWZhbWlseTogRjE7DQogICAgY29sb3I6Y3lhbjsNCn0NCg0KaDEsaDIsaDMsaDQsaDUsaDYscCwgdGFibGUgew0KICBmb250LWZhbWlseTogRjE7DQogIGNvbG9yOiBjeWFuDQp9DQpgYGANCg0KDQoNCmBgYHtyIGNodW5rLXNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGV2YWwgPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICAgI3Jlc3VsdHMgPSAiaG9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBGQUxTRSwgY2FjaGUucGF0aCA9ICIvY2FjaGVzLyIsIGNvbW1lbnQgPSAiIz4iLA0KICAgICAgICAgICAgICAgICAgICAgICNmaWcud2lkdGggPSA3LCAjZmlnLmhlaWdodD0gNywgICANCiAgICAgICAgICAgICAgICAgICAgICAjb3V0LndpZHRoID0gNywgb3V0LmhlaWdodCA9IDcsDQogICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSBUUlVFLCAgZmlnLnNob3cgPSAiaG9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFzcCA9IDAuNjI4LCBvdXQud2lkdGggPSAiNzUlIiwgZmlnLmFsaWduID0gImNlbnRlciIpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZGV2ID0gInBuZyIsIGRldi5hcmdzID0gbGlzdCh0eXBlID0gImNhaXJvLXBuZyIpKQ0KYGBgDQoNCmBgYHtyIG9wdGlvbnMtc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCm9wdGlvbnMoc2NpcGVuID0gOTk5KSAjLSBwYXJhIHF1aXRhciBsYSBub3RhY2nDs24gY2llbnTDrWZpY2ENCm9wdGlvbnMoInlhbWwuZXZhbC5leHByIiA9IFRSVUUpIA0KYGBgDQoNCg0KYGBge3Iga2xpcHB5LCBlY2hvID0gRkFMU0V9DQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoInRvcCIsICJyaWdodCIpKSAjLSByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpgYGANCg0KDQoNCjxociBjbGFzcz0ibGluZWEtYmxhY2siPg0KDQo8IS0tIEVsIHDDoXJyYWZvIGRlIGFiYWpvIGhhcyBkZSBkZWphcmxvIGNhc2kgaWd1YWwsIHNvbG8gSEFTIGRlIFNVU1RJVFVJUiAicGVyZXpwNDQiIHBvciB0dSB1c3VhcmlvIGRlIEdpdGh1Yi0tPg0KVHJhYmFqbyBlbGFib3JhZG8gcGFyYSBsYSBhc2lnbmF0dXJhICJQcm9ncmFtYWNpw7NuIHkgbWFuZWpvIGRlIGRhdG9zIGVuIGxhIGVyYSBkZWwgQmlnIERhdGEiIGRlIGxhIFVuaXZlcnNpdGF0IGRlIFZhbMOobmNpYSBkdXJhbnRlIGVsIGN1cnNvIDIwMjEtMjAyMi4gRWwgcmVwbyBkZWwgdHJhYmFqbyBlc3TDoSBbYXF1w61dKGh0dHBzOi8vZ2l0aHViLmNvbS9jYXlldGFubzEwOC90cmFiYWpvX0JpZ0RhdGFfZXF1aXBvKXt0YXJnZXQ9Il9ibGFuayJ9LiANCg0KPCEtLSBFbCBww6FycmFmbyBkZSBhYmFqbyBoYXMgZGUgZGVqYXJsbyBleGFjdGFtZW50ZSBpZ3VhbCwgTk8gaGFzIGRlIGNhbWJpYXIgbmFkYS0tPg0KDQpMYSBww6FnaW5hIHdlYiBkZSBsYSBhc2lnbmF0dXJhIHkgbG9zIHRyYWJham9zIGRlIG1pcyBjb21wYcOxZXJvcyBwdWVkZW4gdmVyc2UgW2FxdcOtXShodHRwczovL3BlcmV6cDQ0LmdpdGh1Yi5pby9pbnRyby1kcy0yMS0yMi13ZWIvMDctdHJhYmFqb3MuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KPGhyIGNsYXNzPSJsaW5lYS1yZWQiPg0KDQojIExpYnJlcsOtYSBkZSBwYXF1ZXRlcw0KDQpgYGB7ciBwYWNrYWdlcy1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGtsaXBweSkgICMtIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJybGVzdXIva2xpcHB5IikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHJpbykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2dhbmltYXRlKQ0KbGlicmFyeShnZ1RoZW1lQXNzaXN0KQ0KbGlicmFyeShnbG9iZTRyKSAgI3JlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJKb2huQ29lbmUvZ2xvYmU0ciIpDQpsaWJyYXJ5KHJlbW90ZXMpIA0KbGlicmFyeShndCkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHRyZWVtYXApICNpbnN0YWxsLnBhY2thZ2VzKHRyZWVtYXApDQpsaWJyYXJ5KGQzdHJlZVIpICNyZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZDN0cmVlUi9kM3RyZWVSIikNCmBgYA0KDQojIENhbXBlw7NuIGRlbCBtdW5kbw0KDQpgYGB7cn0NCiMgYXF1aSBpcsOhIGZvdG8geSBjb3NpbGxhcyBkZWwgY2FtcGVvbiBkZSBlc3RlIGZpbmRlDQpgYGANCg0KDQoNCiMgSGlzdG9yaWEgZGUgbGEgRjENCg0KDQojIExPR09TIERFIExBIEZPUk1VTEEgMSAgey50YWJzZXR9DQoNCiMjIExvZ28gZGUgMTk4NSBhIDE5ODYNCg0KDQo8Y2VudGVyPg0KIVtMb2dvIGRlIDE5ODUgYSAxOTg2XSguL2ltYWdlbmVzL2xvZ29zLzE5ODUtMTk4Ni5wbmcpe3dpZHRoPTQwMCBoZWlnaHQ9NzB9DQo8L2NlbnRlcj4NCg0KDQoNCg0KDQoNCiMjIExvZ28gZGUgMTk4NyBhIDE5OTMNCjxjZW50ZXI+DQohW0xvZ28gZGUgMTk4NyBhIDE5OTNdKC4vaW1hZ2VuZXMvbG9nb3MvMTk4Ny0xOTkzLmpwZyl7d2lkdGg9MjUwIGhlaWdodD0zMDB9DQo8L2NlbnRlcj4NCg0KIyMgTG9nbyBkZSAxOTk0IGEgMjAxNw0KPGNlbnRlcj4NCiFbTG9nbyBkZSAxOTk0IGEgMjAxN10oLi9pbWFnZW5lcy9sb2dvcy8xOTk0LTIwMTcucG5nKXt3aWR0aD00NTAgaGVpZ2h0PTMwMH0NCjwvY2VudGVyPg0KIyMgTG9nbyBBY3R1YWwNCjxjZW50ZXI+DQohW0xPR08gZGVzZGUgMjAxOCBoYXN0YSBsYSBhY3R1YWxpZGFkXSguL2ltYWdlbmVzL2xvZ29zLzIwMTgtLnBuZyl7d2lkdGg9NDAwIGhlaWdodD0zMDB9DQo8L2NlbnRlcj4NCg0KDQojIENvY2hlcw0KPCEtLS0NCmFxdcOtIGludGVudGFyZW1vcyBtZXRlciBsYSB0cmFuc2ljaW9uIGRlIGltw6FlbmVzDQotLT4NCg0KDQojIGRhdG9zIFByb3RhZ29uaXN0YXMNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCiMtLS1QUkVQQVJBQ0lPTiBERSBMT1MgREFUT1MNCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KI3N0cihyZXN1bHRhZG9zKQ0KI3N0cihwaWxvdG9zKQ0KI3BpbG90b3NbLCBjKDEpXSA8LSBzYXBwbHkocGlsb3Rvc1ssIGMoMSldLCBhcy5udW1lcmljKQ0KI3Jlc3VsdGFkb3NbLCBjKDMsNiw5KV0gPC0gc2FwcGx5KHJlc3VsdGFkb3NbLCBjKDMsNiw5KV0sIGFzLm51bWVyaWMpDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojbnVtZXJvIGRlIGNhcnJlcmFzIHF1ZSBoYSBjb3JyaWRvIGNhZGEgcGlsb3RvDQoNCiNleHBsaWNhY2lvbiBkZSBsbyBxdWUgaGFnbywgbm8gc2UgcG9ycXVlIGxhIHZhcmlhYmxlIHN1bWF0b3JpbyBubyBsYSBkZXRlY3RhIGNvbW8gbnVtZXJpY2EgYXVucXVlIGxhIHBhc2UgYSBudW1lcmljYSwgcG9yIHRhbnRvIGFsIG9yZGVuYXIgY29uIHNsaWNlIG1heCBubyBmdW5jaW9uYSwgbG8gcXVlIGhlIGhlY2hvIGVzIHVzYXIgbGEgZnVuY2lvbiBhcnJhbmdlLCBxdWUgb3JkZW5hIGRlIG1lbm9yIGEgbWF5b3IsIHBlcm8gY29tbyBxdWVyZW1vcyBsb3MgcXVlIG1hcyBjYXJyZXJhcyBoYW4gY29ycmlkbywgbm8gbWUgc2lydmUgZGUgbWVub3IgYSBtYXlvciwgcG9yIHRhbnRvIGhlIG11bHRpcGxpY2FkbyBsYSB2YXJpYWJsZSBkZWwgc3VtYXRvcmlvIHBvciAtMSwgaGUgdXNhZG8gYXJyYW5nZSBwYXJhIHF1ZSBsb3MgcXVlIG3DoXMgY2FycmVyYXMgdGllbmVuIHNhbGdhbiBwcmltZXJvLCB5IGx1ZWdvIGhlIHZ1ZWx0byBhIG11bHRpcGxpY2FyIHBvciAtMS4gbHVlZ28gaGUgY29naWRvIG1heW9yZXMgZGUgMjAyIGNhcnJlcmFzLCBxdWUgc29uIGxvcyAyMCBxdWUgbcOhcyB0aWVuZW4sIHBvcnF1ZSBzaSBoYWdvIHNsaWNlIHNlIGRlc2N1YWRyYSB5IHRlIGRldnVlbHZlIGVsIGRmIGRlbCBwcmluY2lwaW8NCg0Kbl9jYXJyZXJhcyA8LSByZXN1bHRhZG9zICU+JSBncm91cF9ieShkcml2ZXJJZCkgJT4lIG11dGF0ZShudW1lcm9fY2FycmVyYXMgPSBzdW0obigpKSkgJT4lIGRpc3RpbmN0KG51bWVyb19jYXJyZXJhcykgJT4lIGFycmFuZ2UoZGVzYyhudW1lcm9fY2FycmVyYXMpKSAjbXV0YXRlKG51bWVyb19jYXJyZXJhc19maW5hbCA9IG51bWVyb19jYXJyZXJhcyotMSkNCg0Kbl9jYXJyZXJhc19ub20gPC0gZnVsbF9qb2luKG5fY2FycmVyYXMsIHBpbG90b3MsIGMgKCJkcml2ZXJJZCIgPSAiZHJpdmVySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBudW1lcm9fY2FycmVyYXMpICAlPiUgIGZpbHRlcihudW1lcm9fY2FycmVyYXMgPj0gMjAyICkgI2xvcyAyMCBxcXVlIG1hcyBjYXJyZXJhcyB0aWVuZW4gKG5vIGZ1bmNpb25hIHVzYXIgc2xpY2VfbWF4KQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBudW1lcm8gZGUgdmljdG9yaWFzIHBvciBwaWxvdG8NCnZpY3RvcmlhcyA8LSByZXN1bHRhZG9zICU+JSBmaWx0ZXIocG9zaXRpb24gPT0gIjEiKSAlPiUgZ3JvdXBfYnkoZHJpdmVySWQpICU+JSBtdXRhdGUobl92aWN0b3JpYXMgPSBzdW0obigpKSkgJT4lIGRpc3RpbmN0KG5fdmljdG9yaWFzKSAlPiUgYXJyYW5nZShkZXNjKG5fdmljdG9yaWFzKSkjbXV0YXRlKG5fdmljdG9yaWFzX2ZpbmFsID0gbl92aWN0b3JpYXMqLTEpDQoNCiNhcXVpIGZ1c2lvbm8gY29uIGVsIGRmIGRlIHBpbG90b3MgcGFyYSBxdWUgYXBhcmV6Y2EgZWwgbm9tYnJlIHkgbm8gc8OzbG8gZWwgSUQgZGVsIHBpbG90byBlbiBjdWVzdGlvbiwgeSBoYWdvIGxvIG1pc21vIHF1ZSBlbiBlbCBhcGFydGFkbyBkZSBhcnJpYmEgcGFyYSBvcmRlbmFyDQp2aWN0b3JpYXNfY29uX25vbWJyZSA8LSBmdWxsX2pvaW4odmljdG9yaWFzLCBwaWxvdG9zLCBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIG5hdGlvbmFsaXR5LCBkcml2ZXJSZWYsIG5fdmljdG9yaWFzKSAgI2xvcyAxMCBjb24gbWFzIHZpY3RvcmlhcywgdG1wIGZ1bmNpb25hIHNsaWNlX21heA0KbWFzX3ZpY3RvcmlhcyA8LSB2aWN0b3JpYXNfY29uX25vbWJyZSAlPiUgIGZpbHRlcihuX3ZpY3RvcmlhcyA+PSAyNSApIA0KDQoNCg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojcmVzdWx0YWRvIG1lZGlvDQoNCnJlc3VsdGFkb3NbLCBjKDcpXSA8LSBzYXBwbHkocmVzdWx0YWRvc1ssIGMoNyldLCBhcy5udW1lcmljKQ0KcmVzdWx0YWRvc1tpcy5uYShyZXN1bHRhZG9zKV0gPC0gMjUgDQoNCnJlc3VsdGFkb19tZWRpbyA8LSAgZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgcG9zaXRpb24pICU+JSBncm91cF9ieShkcml2ZXJJZCkgJT4lIG11dGF0ZShyZXN1bHRfbWVkaW8gPSBtZWFuKHBvc2l0aW9uKSkgJT4lIGRpc3RpbmN0IChkcml2ZXJJZCwgZHJpdmVyUmVmLCByZXN1bHRfbWVkaW8pICU+JSBhcnJhbmdlKHJlc3VsdF9tZWRpbykNCg0KI3Jlc3VsdGFkbyBtZWRpbyBlbiBjbGFzaWZpY2FjaW9uDQpyZXN1bHRhZG9fbWVkaW9fY2xhcyA8LSAgZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgZ3JpZCkgJT4lIGdyb3VwX2J5KGRyaXZlcklkKSAlPiUgbXV0YXRlKHJlc3VsdF9tZWRpb19jbGFzID0gbWVhbihncmlkKSkgJT4lIGRpc3RpbmN0IChkcml2ZXJJZCwgZHJpdmVyUmVmLCByZXN1bHRfbWVkaW9fY2xhcykgICU+JSBmaWx0ZXIocmVzdWx0X21lZGlvX2NsYXMgPiAwKSAlPiUgYXJyYW5nZShyZXN1bHRfbWVkaW9fY2xhcykgIA0KDQoNCiNudW1lcm8gZGUgdnVlbHRhcyBsaWRlcmFuZG8NCg0KDQojcHVudG9zIHBvciBjYXJyZXJhIChwdW50b3MvY2FycmVyYSkNCg0KcHVudG9zX3hfY2FycmVyYSA8LSAgZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgcG9pbnRzKSAlPiUgZnVsbF9qb2luKC4sIG5fY2FycmVyYXMsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBncm91cF9ieShkcml2ZXJJZCkgJT4lIG11dGF0ZSh0b3RhbF9wdW50b3MgPSBzdW0ocG9pbnRzKSkgJT4lIGRpc3RpbmN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG51bWVyb19jYXJyZXJhcywgdG90YWxfcHVudG9zKSAlPiUgbXV0YXRlKG1lZGlhX3B1bnRvcyA9IHRvdGFsX3B1bnRvcy9udW1lcm9fY2FycmVyYXMpICU+JSBhcnJhbmdlKGRlc2MobWVkaWFfcHVudG9zKSkNCg0KYGBgDQoNCg0KIyBHcmFmaWNvIG3DoXMgdmljdG9yaWFzDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQojc2UgbmVjZXNpdGEgIm1hc192aWN0b3JpYXMiDQoNCiNoYXkgcXVlIGRhcmxlIGZvcm1hdG8geSBtaXJhciBsbyBkZSBhbmltYXJsbyBwb3IgZmVjaGENCg0KDQpnZ19tYXNfdmljdG9yaWFzIDwtIGdncGxvdChtYXNfdmljdG9yaWFzLCBhZXMoeCA9IHJlb3JkZXIoZHJpdmVyUmVmLCBuX3ZpY3RvcmlhcyksIHkgPSBuX3ZpY3RvcmlhcyApKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGxhYnMoeCA9ICJQaWxvdG8iICwgeSA9ICJOw7ptZXJvIGRlIHZpY3RvcmlhcyIpDQpnZ19tYXNfdmljdG9yaWFzDQojdHJhYmFqbyAtLT4gZGFybGUgZm9ybWF0byBjaHVsbywgeWEgdmVyZW1vcyBlc3RlIHB1ZW50ZSBzaSBsZSBwb2RlbW9zIG1ldGVyIGRpbsOhbWljbyBvIHF1ZQ0KDQogICAgICAgICAgICAgICAgICAgICANCmBgYA0KDQoNCiMjIFBhcnJpbGxhIGRlIHBpbG90b3MgMjAyMSB0YWJsYQ0KDQpgYGB7cn0NCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KY2FycmVyYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3JhY2VzLmNzdiIpDQpsaWJyYXJ5KHN0cmluZ3IpDQoNCg0KcGlsb3Rvc18yMDIxIDwtIGZ1bGxfam9pbihjYXJyZXJhcywgcmVzdWx0YWRvcywgYygicmFjZUlkIiA9ICJyYWNlSWQiKSApICU+JSANCiAgZnVsbF9qb2luKC4scGlsb3RvcywgYygiZHJpdmVySWQiPSJkcml2ZXJJZCIpKSAlPiUgDQogIGZpbHRlcih5ZWFyPT0iMjAyMSIpICU+JSANCiAgc2VsZWN0KGZvcmVuYW1lLHN1cm5hbWUsIHllYXIpICU+JSBkaXN0aW5jdChmb3JlbmFtZSxzdXJuYW1lKSAlPiUgbmEub21pdCgpICU+JSBhcnJhbmdlKHN1cm5hbWUpICU+JSBzdHJfcmVwbGFjZV9hbGwoLiwgIsODwqkiLCAiw6kiKSAlPiUgc3RyX3JlcGxhY2VfYWxsKC4sICLDg8KkIiwgIsOkIikgJT4lIHN0cl9yZXBsYWNlX2FsbCguLCAiw4PCtiIsICLDtiIpDQoNCm5vbWJyZXNfbm9ybWFsZXMgPC0gYygiQWxvbnNvIiwgIkJvdHRhcyIsICJHYXNseSIsICJHaW92aW5henppIiwgIkhhbWlsdG9uIiwgIkxhdGlmaSIsICJMZWNsZXJjIiwgIk1hemVwaW4iLCAiTm9ycmlzIiwgIk9jb24iLCAiUMOpcmV6IiwgIlLDpGlra8O2bmVuIiwgIlJpY2NpYXJkbyIsICJSdXNzZWxsIiwgIlNhaW56IiwgIlNjaHVtYWNoZXIiLCAiU3Ryb2xsIiwgIlRzdW5vZGEiLCAiVmVyc3RhcHBlbiIsICJWZXR0ZWwiKQ0KDQpwaWxvdG9zXzIwMjEgPC0gIGZ1bGxfam9pbihjYXJyZXJhcywgcmVzdWx0YWRvcywgYygicmFjZUlkIiA9ICJyYWNlSWQiKSApICU+JSANCiAgZnVsbF9qb2luKC4scGlsb3RvcywgYygiZHJpdmVySWQiPSJkcml2ZXJJZCIpKSAlPiUgDQogIGZpbHRlcih5ZWFyPT0iMjAyMSIpICU+JSANCiAgc2VsZWN0KGZvcmVuYW1lLHN1cm5hbWUsIHllYXIpICU+JSBkaXN0aW5jdChmb3JlbmFtZSxzdXJuYW1lKSAlPiUgbmEub21pdCgpICU+JSBhcnJhbmdlKHN1cm5hbWUpICU+JSBhZGRfY29sdW1uKG5vbWJyZXNfbm9ybWFsZXMpICANCiANCg0KIyBQw4PCqXJleg0KIyBSw4PCpGlra8ODwrZuZW4NCmZvdG9zX3BpbF8yMDIxIDwtIGMoIi4vaW1hZ2VuZXMvcGlsb3Rvcy9hbG9uc28ucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9ib3R0YXMucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9nYXNseS5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL2dpb3ZpbmF6emkuanBnIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9oYW1pbHRvbi5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL2xhdGlmaS5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL2xlY2xlcmMucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9tYXplcGluLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3Mvbm9ycmlzLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3Mvb2Nvbi5qcGciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3BlcmV6LnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvcmFpa2tvbmVuLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvcmljY2lhcmRvLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvcnVzc2VsbC5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3NhaW56LnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvbWljay5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3N0cm9sbC5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3RzdW5vZGEucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy92ZXJzdGFwcGVuLmpwZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvdmV0dGVsLnBuZyIpDQoNCmZvdG9zX3BhaXNfMjAyMSA8LSBjKCIuL2ltYWdlbmVzL3BhaXNlcy9lc3BhbnlhLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy9maW5sYW5kaWEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2ZyYW5jaWEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2l0YWxpYS5wbmciLCIuL2ltYWdlbmVzL3BhaXNlcy91ay5wbmciLCAiLi9pbWFnZW5lcy9wYWlzZXMvY2FuYWRhLnBuZyIsIi4vaW1hZ2VuZXMvcGFpc2VzL21vbmFjby5wbmciLCAiLi9pbWFnZW5lcy9wYWlzZXMvcnVzaWEucG5nIiwiLi9pbWFnZW5lcy9wYWlzZXMvdWsucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2ZyYW5jaWEucG5nIiwiLi9pbWFnZW5lcy9wYWlzZXMvbWV4aWNvLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy9maW5sYW5kaWEucG5nIiwiLi9pbWFnZW5lcy9wYWlzZXMvYXVzdHJhbGlhLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy91ay5wbmciLCIuL2ltYWdlbmVzL3BhaXNlcy9lc3BhbnlhLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy9hbGVtYW5pYS5wbmciLCIuL2ltYWdlbmVzL3BhaXNlcy9jYW5hZGEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2phcG9uLnBuZyIsIi4vaW1hZ2VuZXMvcGFpc2VzL2hvbGFuZGEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2FsZW1hbmlhLnBuZyIpDQoNCmZvdG9zX2VzY18yMDIxIDwtIGMoIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9hbHBpbmUucG5nIiwiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL21lcmNlZGVzLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9hbHBoYXRhdXJpLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvYWxmYXJvbWVvLmpwZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9tZXJjZWRlcy5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL3dpbGxpYW1zLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9mZXJyYXJpLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvaGFhcy5wbmciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvbWNsYXJlbi5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL2FscGluZS5wbmciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvcmVkYnVsbC5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL2FsZmFyb21lby5qcGciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvbWNsYXJlbi5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL3dpbGxpYW1zLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9mZXJyYXJpLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvaGFhcy5wbmciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvYXN0b24ucG5nIiwgIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9hbHBoYXRhdXJpLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9yZWRidWxsLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvYXN0b24ucG5nIikNCg0KcGlsb3Rvc18yMDIxIDwtIHBpbG90b3NfMjAyMSAlPiUNCiAgYWRkX2NvbHVtbihmb3Rvc19waWxfMjAyMSwgZm90b3NfcGFpc18yMDIxLCBmb3Rvc19lc2NfMjAyMSkgJT4lIHNlbGVjdChub21icmVzX25vcm1hbGVzLCBmb3Rvc19waWxfMjAyMSwgZm90b3NfcGFpc18yMDIxLCBmb3Rvc19lc2NfMjAyMSkNCg0KbGlicmFyeShndCkNCm11bmRpYWxfMjAyMSA8LSBwaWxvdG9zXzIwMjEgJT4lIGd0KCkgJT4lIHRleHRfdHJhbnNmb3JtKCBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKGZvdG9zX3BpbF8yMDIxKSksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojpsb2NhbF9pbWFnZSh4LCBoZWlnaHQgPSA4MCl9KSAlPiUgdGV4dF90cmFuc2Zvcm0oIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoZm90b3NfcGFpc18yMDIxKSksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojpsb2NhbF9pbWFnZSh4LCBoZWlnaHQgPSA4MCl9KSAlPiUgdGV4dF90cmFuc2Zvcm0oIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoZm90b3NfZXNjXzIwMjEpKSwgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OmxvY2FsX2ltYWdlKHgsIGhlaWdodCA9IDgwKX0pICU+JSB0YWJfaGVhZGVyKHRpdGxlID0gbWQoIioqUGlsb3RvcyAyMDIxKioiKSwgc3VidGl0bGUgPSBtZCgiUGFycmlsbGEiKSkgJT4lICAgY29sc19sYWJlbCgNCiAgICBub21icmVzX25vcm1hbGVzID0gaHRtbCgiIiksDQogICAgZm90b3NfcGlsXzIwMjEgPSBodG1sKCIiKSwNCiAgICBmb3Rvc19wYWlzXzIwMjEgPSBodG1sKCIiKSwNCiAgICBmb3Rvc19lc2NfMjAyMSA9IGh0bWwoIiIpKSAlPiUgIA0KICB0YWJfb3B0aW9ucyh0YWJsZS5iYWNrZ3JvdW5kLmNvbG9yID0gImdyYXkxMyIsICAgdGFibGUuZm9udC5jb2xvci5saWdodCA9ICJjeWFuIikgJT4lIA0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIsDQogIGNvbHVtbnMgPSBldmVyeXRoaW5nKCkpDQoNCg0KbXVuZGlhbF8yMDIxDQpgYGANCg0KDQojIyBFc3Bhw7FvbGVzIHBvciBsYSBGMQ0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiNwaWxvdG9zIGVzcGHDsW9sZXMNCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KDQpwaWxvdG9zX2VzcCA8LSBwaWxvdG9zICU+JSBmaWx0ZXIobmF0aW9uYWxpdHkgPT0gIlNwYW5pc2giKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5KSANCg0KDQojbWFzIHZpY3RvcmlhcyBkZSBwaWxvdG9zIGVzcGHDsW9sZXMNCm1hc192aWN0b3JpYXNfZXNwIDwtIGZ1bGxfam9pbih2aWN0b3JpYXNfY29uX25vbWJyZSwgcGlsb3RvcywgYyAoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgZmlsdGVyKG5hdGlvbmFsaXR5LnggPT0gIlNwYW5pc2giKSAlPiUgIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLngsIG5fdmljdG9yaWFzLCBuYXRpb25hbGl0eS54KSANCg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KYGBgDQoNCg0KDQojIyBFc2N1ZGVyw61hcyBjYW1wZW9uYXMgey50YWJzZXR9DQoNCiMjIyBQb3IgdGFtYcOxbw0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRSwgaW5jbHVkZSA9IEZBTFNFfQ0KI2RhdG9zIGRlIGVzY3VkZXJpYXMgcGEgcXVpZW4gcXVpZXJhIGhhY2VyIGFsZ28NCmVzY3VkZXJpYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9ycy5jc3YiKQ0KZXNjdWRlcmlhczIgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9yX3N0YW5kaW5ncy5jc3YiKQ0KcmVzdWx0X2VzY3VkZXJpYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9yX3Jlc3VsdHMuY3N2IikNCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KY2FycmVyYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3JhY2VzLmNzdiIpDQojZXNjdWRlcmlhc2VzcCA8LSBlc2N1ZGVyaWFzICU+JSBmaWx0ZXIobmF0aW9uYWxpdHkgPT0gIlNwYW5pc2giKSAjZXNjdWRlcmlhcyBlc3Bhw7FvbGFzDQoNCmNhbXBlb25lc19lc2MgPC0gZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsIGMoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgZnVsbF9qb2luKC4sIGNhcnJlcmFzLCBjKCJyYWNlSWQiID0gInJhY2VJZCIpKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIHJvdW5kKSAlPiUgZnVsbF9qb2luKC4sIGVzY3VkZXJpYXMsIGMoImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBuYXRpb25hbGl0eS54LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIG5hbWUsIHJvdW5kKSAlPiUgIGdyb3VwX2J5KHllYXIsIGRyaXZlclJlZikgJT4lICBtdXRhdGUocHVudG9zX3RvdGFsZXMgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lIHNsaWNlX21heChwdW50b3NfdG90YWxlcywgbj0xKSAlPiUgc2VsZWN0KG5hbWUsIGRyaXZlclJlZikgJT4lIGdyb3VwX2J5KG5hbWUsIGRyaXZlclJlZikgJT4lIG11dGF0ZSh0b3RhbF9jYW1wID0gc3VtKCBOTiA9IG4oKSkpICU+JSBhcnJhbmdlKG5hbWUpIA0KDQoNCmNhbXBlb25lc19lc2MgPC0gY2FtcGVvbmVzX2VzY1shKGNhbXBlb25lc19lc2MkZHJpdmVyUmVmID09ICdtYXhfdmVyc3RhcHBlbicpLF0gDQoNCmxpYnJhcnkodHJlZW1hcCkNCmxpYnJhcnkoZDN0cmVlUikNCg0KDQojIGJhc2ljIHRyZWVtYXANCmdnX2VzY19jYW1wZW9uZXMgPC0gdHJlZW1hcChjYW1wZW9uZXNfZXNjLA0KICAgICAgICAgICAgaW5kZXg9YygibmFtZSIsImRyaXZlclJlZiIpLA0KICAgICAgICAgICAgdlNpemU9InRvdGFsX2NhbXAiLA0KICAgICAgICAgICAgdHlwZT0iaW5kZXgiLA0KICAgICAgICAgICAgdkNvbG9yID0gIm5hbWUiLA0KICAgICAgICAgICAgZm9udHNpemUubGFiZWxzPWMoMTUsMjApLA0KICAgICAgICAgICAgYmcubGFiZWxzPWMoInRyYW5zcGFyZW50IiksDQogICAgICAgICAgICBwYWxldHRlID0gIlNldDIiLA0KICAgICAgICAgICAgYWxpZ24ubGFiZWxzPWxpc3QoDQogICAgICAgICAgICAgIGMoImNlbnRlciIsICJjZW50ZXIiKSwgDQogICAgICAgICAgICAgIGMoImNlbnRlciIsICJib3R0b20iKSksDQogICAgICAgICAgICB0aXRsZSA9ICJFc2N1ZGVyw61hcyBjb24gbcOhcyBjYW1wZW9uZXMiLA0KICAgICAgICAgICAgdGl0bGUubGVnZW5kID0gIkVzY3VkZXLDrWFzIikgICANCg0KYGBgDQoNCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCiNkYXRvcyBkZSBlc2N1ZGVyaWFzIHBhIHF1aWVuIHF1aWVyYSBoYWNlciBhbGdvDQojZXNjdWRlcmlhcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvY29uc3RydWN0b3JzLmNzdiIpDQojZXNjdWRlcmlhczIgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9yX3N0YW5kaW5ncy5jc3YiKQ0KI3Jlc3VsdF9lc2N1ZGVyaWFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9jb25zdHJ1Y3Rvcl9yZXN1bHRzLmNzdiIpDQoNCiNwaWxvdG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9kcml2ZXJzLmNzdiIpDQojcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KI2NhcnJlcmFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yYWNlcy5jc3YiKQ0KI2VzY3VkZXJpYXNlc3AgPC0gZXNjdWRlcmlhcyAlPiUgZmlsdGVyKG5hdGlvbmFsaXR5ID09ICJTcGFuaXNoIikgI2VzY3VkZXJpYXMgZXNwYcOxb2xhcw0KDQojY2FtcGVvbmVzX2VzYyA8LSBmdWxsX2pvaW4ocGlsb3RvcywgcmVzdWx0YWRvcywgYygiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBmdWxsX2pvaW4oLiwgY2FycmVyYXMsIGMoInJhY2VJZCIgPSAicmFjZUlkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgbmF0aW9uYWxpdHksIGNvbnN0cnVjdG9ySWQsIHBvaW50cywgeWVhciwgcm91bmQpICU+JSBmdWxsX2pvaW4oLiwgZXNjdWRlcmlhcywgYygiY29uc3RydWN0b3JJZCIgPSAiY29uc3RydWN0b3JJZCIpKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LngsIGNvbnN0cnVjdG9ySWQsIHBvaW50cywgeWVhciwgbmFtZSwgcm91bmQpICU+JSAgZ3JvdXBfYnkoeWVhciwgZHJpdmVyUmVmKSAlPiUgIG11dGF0ZShwdW50b3NfdG90YWxlcyA9IGN1bXN1bShwb2ludHMpKSAlPiUgdW5ncm91cCgpICU+JSBncm91cF9ieSh5ZWFyKSAlPiUgc2xpY2VfbWF4KHB1bnRvc190b3RhbGVzLCBuPTEpICU+JSBzZWxlY3QobmFtZSwgZHJpdmVyUmVmKSAlPiUgZ3JvdXBfYnkobmFtZSwgZHJpdmVyUmVmKSAlPiUgbXV0YXRlKHRvdGFsX2NhbXAgPSBzdW0oIE5OID0gbigpKSkgJT4lIGFycmFuZ2UobmFtZSkgDQoNCg0KI2NhbXBlb25lc19lc2MgPC0gY2FtcGVvbmVzX2VzY1shKGNhbXBlb25lc19lc2MkZHJpdmVyUmVmID09ICdtYXhfdmVyc3RhcHBlbicpLF0gDQoNCiNsaWJyYXJ5KHRyZWVtYXApDQojbGlicmFyeShkM3RyZWVSKQ0KDQoNCiMgYmFzaWMgdHJlZW1hcA0KI2dnX2VzY19jYW1wZW9uZXMgPC0gdHJlZW1hcChjYW1wZW9uZXNfZXNjLA0KICAgICAgICAgICAgI2luZGV4PWMoIm5hbWUiLCJkcml2ZXJSZWYiKSwNCiAgICAgICAgICAgICN2U2l6ZT0idG90YWxfY2FtcCIsDQogICAgICAgICAgICAjdHlwZT0iaW5kZXgiLA0KICAgICAgICAgICAgI3ZDb2xvciA9ICJuYW1lIiwNCiAgICAgICAgICAgICNmb250c2l6ZS5sYWJlbHM9YygyNSwxNyksDQogICAgICAgICAgICAjYmcubGFiZWxzPWMoInRyYW5zcGFyZW50IiksDQogICAgICAgICAgICAjcGFsZXR0ZSA9ICJTZXQyIiwNCiAgICAgICAgICAgICNhbGlnbi5sYWJlbHM9bGlzdCgNCiAgICAgICAgICAgICAgI2MoImNlbnRlciIsICJjZW50ZXIiKSwgDQogICAgICAgICAgICAgICNjKCJjZW50ZXIiLCAiYm90dG9tIikpLA0KICAgICAgICAgICAgI3RpdGxlID0gIkVzY3VkZXLDrWFzIGNvbiBtw6FzIGNhbXBlb25lcyIsDQogICAgICAgICAgICAjdGl0bGUubGVnZW5kID0gIkVzY3VkZXLDrWFzIikgICANCg0KYGBgDQoNCmBgYHtyLCBmaWcuYWxpZ249J2NlbnRlcid9DQoNCmludGVyX2NhbXAgPC0gZDN0cmVlMihnZ19lc2NfY2FtcGVvbmVzICwgIHJvb3RuYW1lID0gIkVzY3VkZXLDrWFzIHkgQ2FtcGVvbmVzIikNCmludGVyX2NhbXANCg0KDQpgYGANCg0KIyMjIEVuIHZhbG9yZXMgYWJzb2x1dG9zDQoNCmBgYHtyfQ0KDQpjYW1wZW9uZXNfZXNjIDwtIGZ1bGxfam9pbihwaWxvdG9zLCByZXN1bHRhZG9zLCBjKCJkcml2ZXJJZCIgPSAiZHJpdmVySWQiKSkgJT4lIGZ1bGxfam9pbiguLCBjYXJyZXJhcywgYygicmFjZUlkIiA9ICJyYWNlSWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBuYXRpb25hbGl0eSwgY29uc3RydWN0b3JJZCwgcG9pbnRzLCB5ZWFyLCByb3VuZCkgJT4lIGZ1bGxfam9pbiguLCBlc2N1ZGVyaWFzLCBjKCJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgbmF0aW9uYWxpdHkueCwgY29uc3RydWN0b3JJZCwgcG9pbnRzLCB5ZWFyLCBuYW1lLCByb3VuZCkgJT4lICBncm91cF9ieSh5ZWFyLCBkcml2ZXJSZWYpICU+JSAgbXV0YXRlKHB1bnRvc190b3RhbGVzID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkgJT4lIGdyb3VwX2J5KHllYXIpICU+JSBzbGljZV9tYXgocHVudG9zX3RvdGFsZXMsIG49MSkgJT4lIHVuZ3JvdXAoKSAlPiUgY291bnQobmFtZSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkNCg0KDQpnZ3Bsb3QoY2FtcGVvbmVzX2VzYywgYWVzKHggPSByZW9yZGVyKG5hbWUsbikseSA9IG4pKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCg0KDQojIEFsb25zbyAoZWwgbmFubykNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQojYWxvbnNvIHZzIGNvbXBhw7Flcm9zIGRlIGVxdWlwbw0KDQpwaWxvdG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9kcml2ZXJzLmNzdiIpDQpyZXN1bHRhZG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yZXN1bHRzLmNzdiIpDQplc2N1ZGVyaWFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9jb25zdHJ1Y3RvcnMuY3N2IikNCmNhcnJlcmFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yYWNlcy5jc3YiKQ0KDQphbG92c2FsbCA8LSBmdWxsX2pvaW4ocGlsb3RvcywgcmVzdWx0YWRvcywgYyAoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgIHNlbGVjdChkcml2ZXJSZWYsIHJlc3VsdElkLCByYWNlSWQsIGNvbnN0cnVjdG9ySWQsIHBvc2l0aW9uLCBwb2ludHMpICU+JSBmdWxsX2pvaW4oLiwgZXNjdWRlcmlhcywgYyAoImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJSZWYsIHJlc3VsdElkLCByYWNlSWQsIGNvbnN0cnVjdG9ySWQsIHBvc2l0aW9uLCBwb3NpdGlvbiwgcG9pbnRzLCBuYW1lKSAlPiUgZnVsbF9qb2luKC4sIGNhcnJlcmFzLCBjICgicmFjZUlkIiA9ICJyYWNlSWQiKSkgJT4lIHNlbGVjdChkcml2ZXJSZWYsIHJlc3VsdElkLCByYWNlSWQsIGNvbnN0cnVjdG9ySWQsIHBvc2l0aW9uLCBwb3NpdGlvbiwgcG9pbnRzLCBuYW1lLngsIHllYXIsIHJvdW5kKQ0KDQojYWxvX3ZzX21hcnF1ZXMgPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyID09IDIwMDEsIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJtYXJxdWVzIiksIHJvdW5kIDw9IDE0KQ0KDQphbG9fdnNfdHJ1bGxpIDwtIGFsb3ZzYWxsICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwMywgMjAwNCksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJ0cnVsbGkiKSkgJT4lIHNsaWNlKDE6MTUsIDE3OjY3KSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX2Zpc2ljaGVsbGEgPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyICVpbiUgYygyMDA1LCAyMDA2KSwgZHJpdmVyUmVmICVpbiUgYygiYWxvbnNvIiwgImZpc2ljaGVsbGEiKSkgICU+JSBncm91cF9ieShkcml2ZXJSZWYsIHllYXIpICU+JSBtdXRhdGUocHVudG9zX2FjdW11bGFkb3MgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKQ0KDQphbG9fdnNfaGFtaWx0b24gPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyICVpbiUgYygyMDA3KSAsZHJpdmVyUmVmICVpbiUgYygiYWxvbnNvIiwgImhhbWlsdG9uIikpICAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX3BpcXVldCA8LSBhbG92c2FsbCAlPiUgZmlsdGVyKHllYXIgJWluJSBjKDIwMDgsIDIwMDkpLCBkcml2ZXJSZWYgJWluJSBjKCJhbG9uc28iLCAicGlxdWV0X2pyIikpICU+JSBzbGljZSgxOjI4LCAzNjo2MykgJT4lIGdyb3VwX2J5KGRyaXZlclJlZiwgeWVhcikgJT4lIG11dGF0ZShwdW50b3NfYWN1bXVsYWRvcyA9IGN1bXN1bShwb2ludHMpKSAlPiUgdW5ncm91cCgpDQoNCiNhbG9fdnNfZ3Jvc2plYW4gPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyID09IDIwMDksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJncm9zamVhbiIpLCByb3VuZCA+PSAxMSkNCg0KYWxvX3ZzX21hc3NhIDwtIGFsb3ZzYWxsICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAxMCwgMjAxMSwgMjAxMyksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJtYXNzYSIpKSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX3JhaWtrb25lbiA8LSBhbG92c2FsbCAlPiUgZmlsdGVyKHllYXIgPT0gMjAxNCwgZHJpdmVyUmVmICVpbiUgYygiYWxvbnNvIiwgInJhaWtrb25lbiIpKSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX2J1dHRvbiA8LSBhbG92c2FsbCAlPiUgZmlsdGVyKHllYXIgJWluJSBjKDIwMTUsIDIwMTYpLCBkcml2ZXJSZWYgJWluJSBjKCJhbG9uc28iLCAiYnV0dG9uIikpICU+JSBncm91cF9ieShkcml2ZXJSZWYsIHllYXIpICU+JSBtdXRhdGUocHVudG9zX2FjdW11bGFkb3MgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKQ0KDQphbG9fdnNfdmFuZG9vcm5lIDwtIGFsb3ZzYWxsICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAxNywgMjAxOCksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJ2YW5kb29ybmUiKSkgJT4lIHNsaWNlKDE6NDUsIDQ3OjgxKSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpJT4lIHVuZ3JvdXAoKSANCg0KYWxvX3ZzX29jb24gPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyID09IDIwMjEsIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJvY29uIikpICU+JSBncm91cF9ieShkcml2ZXJSZWYsIHllYXIpICU+JSBtdXRhdGUocHVudG9zX2FjdW11bGFkb3MgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKQ0KDQpBTE9fVlNfQUxMIDwtIGZ1bGxfam9pbihhbG9fdnNfdHJ1bGxpLCBhbG9fdnNfZmlzaWNoZWxsYSwgYygiZHJpdmVyUmVmIj0gImRyaXZlclJlZiIsICJyZXN1bHRJZCIgPSAicmVzdWx0SWQiLCAicmFjZUlkIiA9ICJyYWNlSWQiLCAiY29uc3RydWN0b3JJZCIgPSAiY29uc3RydWN0b3JJZCIsICJwb3NpdGlvbiIgPSAicG9zaXRpb24iLCAicG9pbnRzIiA9ICJwb2ludHMiLCAibmFtZS54IiA9ICJuYW1lLngiLCAieWVhciIgPSAieWVhciIsICJyb3VuZCIgPSAicm91bmQiICwgInB1bnRvc19hY3VtdWxhZG9zIiA9ICJwdW50b3NfYWN1bXVsYWRvcyIpKSAlPiUgDQogIGZ1bGxfam9pbiguLCBhbG9fdnNfaGFtaWx0b24sIGMoImRyaXZlclJlZiI9ICJkcml2ZXJSZWYiLCAicmVzdWx0SWQiID0gInJlc3VsdElkIiwgInJhY2VJZCIgPSAicmFjZUlkIiwgImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiLCAicG9zaXRpb24iID0gInBvc2l0aW9uIiwgInBvaW50cyIgPSAicG9pbnRzIiwgIm5hbWUueCIgPSAibmFtZS54IiwgInllYXIiID0gInllYXIiLCAicm91bmQiID0gInJvdW5kIiwgInB1bnRvc19hY3VtdWxhZG9zIiA9ICJwdW50b3NfYWN1bXVsYWRvcyIpKSAlPiUgDQogIGZ1bGxfam9pbiguLCBhbG9fdnNfcGlxdWV0LCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkgJT4lIA0KICBmdWxsX2pvaW4oLiwgYWxvX3ZzX21hc3NhLCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkgICU+JSANCiAgZnVsbF9qb2luKC4sIGFsb192c19yYWlra29uZW4sIGMoImRyaXZlclJlZiI9ICJkcml2ZXJSZWYiLCAicmVzdWx0SWQiID0gInJlc3VsdElkIiwgInJhY2VJZCIgPSAicmFjZUlkIiwgImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiLCAicG9zaXRpb24iID0gInBvc2l0aW9uIiwgInBvaW50cyIgPSAicG9pbnRzIiwgIm5hbWUueCIgPSAibmFtZS54IiwgInllYXIiID0gInllYXIiLCAicm91bmQiID0gInJvdW5kIiwgInB1bnRvc19hY3VtdWxhZG9zIiA9ICJwdW50b3NfYWN1bXVsYWRvcyIpKSAlPiUgDQogIGZ1bGxfam9pbiguLCBhbG9fdnNfYnV0dG9uLCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkgJT4lIA0KICBmdWxsX2pvaW4oLiwgYWxvX3ZzX3ZhbmRvb3JuZSwgYygiZHJpdmVyUmVmIj0gImRyaXZlclJlZiIsICJyZXN1bHRJZCIgPSAicmVzdWx0SWQiLCAicmFjZUlkIiA9ICJyYWNlSWQiLCAiY29uc3RydWN0b3JJZCIgPSAiY29uc3RydWN0b3JJZCIsICJwb3NpdGlvbiIgPSAicG9zaXRpb24iLCAicG9pbnRzIiA9ICJwb2ludHMiLCAibmFtZS54IiA9ICJuYW1lLngiLCAieWVhciIgPSAieWVhciIsICJyb3VuZCIgPSAicm91bmQiLCAicHVudG9zX2FjdW11bGFkb3MiID0gInB1bnRvc19hY3VtdWxhZG9zIikpICU+JSANCiAgZnVsbF9qb2luKC4sIGFsb192c19vY29uLCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkNCg0Kb2JqZXRvc19ub19ib3JyYXIgPC0gYygiQUxPX1ZTX0FMTCIsICJuX2NhcnJlcmFzX25vbSIsICJ2aWN0b3JpYXNfY29uX25vbWJyZSIpDQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIG9iamV0b3Nfbm9fYm9ycmFyXSkNCg0KDQpnYygpICNpbnN0cnVjY2lvbiBwYXJhIHF1ZSBjYXJndWUgZWwgZ3JhZmljbywgYWwgc2VyIHRhbiBjb21wbGVqbyBkYSBlcnJvciBkZSBubyBzw6kgcXXDqSBwZXJvIGNvbiBlc3RvIGZ1bmNpb25hDQpnZ2Fsb192c19hbGwgPC0gZ2dwbG90KGRhdGEgPSBBTE9fVlNfQUxMLCBhZXMocm91bmQsIHB1bnRvc19hY3VtdWxhZG9zLCBjb2xvciA9IGRyaXZlclJlZikpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKyANCiAgbGFicyh0aXRsZSA9ICJBbG9uc28gY29udHJhIGVsIG11bmRvIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJsZSBkYXMgdW4gY2FydG9uIGNvbiBydWVkYXMgeSBhw7puIHRlIHNhY2EgcHVudG9zIiwNCiAgICAgICB5ID0gIlB1bnRvcyIsIHggPSAiIikgKyBmYWNldF93cmFwKCB+IHllYXIpICsgdHJhbnNpdGlvbl9yZXZlYWwocm91bmQpDQoNCiNnZ2Fsb192c19hbGwNCg0KDQpgYGANCg0KIyBDYW1wZW9uZXMgZGVsIG11bmRvDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCnBpbG90b3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2RyaXZlcnMuY3N2IikNCnJlc3VsdGFkb3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3Jlc3VsdHMuY3N2IikNCmVzY3VkZXJpYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9ycy5jc3YiKQ0KY2FycmVyYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3JhY2VzLmNzdiIpDQoNCg0KDQpjYW1wZW9uZXMgPC0gZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsIGMoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgZnVsbF9qb2luKC4sIGNhcnJlcmFzLCBjKCJyYWNlSWQiID0gInJhY2VJZCIpKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIHJvdW5kKSAlPiUgZnVsbF9qb2luKC4sIGVzY3VkZXJpYXMsIGMoImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBuYXRpb25hbGl0eS54LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIG5hbWUsIHJvdW5kKSAlPiUgIGdyb3VwX2J5KHllYXIsIGRyaXZlclJlZikgJT4lICBtdXRhdGUocHVudG9zX3RvdGFsZXMgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lIHNsaWNlX21heChwdW50b3NfdG90YWxlcywgbj0xKSAlPiUgdW5ncm91cCgpICU+JSBncm91cF9ieShkcml2ZXJSZWYpJT4lIG11dGF0ZSh0b3RhbF9jYW1wZW9uYXRvcyA9IHN1bShOTiA9IG4oKSkpICU+JSBkaXN0aW5jdChkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LngsIHRvdGFsX2NhbXBlb25hdG9zKSAlPiUgYXJyYW5nZShuYXRpb25hbGl0eS54LCB0b3RhbF9jYW1wZW9uYXRvcykNCiAgDQpjYW1wZW9uZXMgPC0gY2FtcGVvbmVzWyEoY2FtcGVvbmVzJGRyaXZlclJlZiA9PSAnbWF4IHZlcnN0YXBwZW4nKSxdDQppZCA8LSByb3duYW1lcyhjYW1wZW9uZXMpDQpjYW1wZW9uZXMgPC0gY2JpbmQoaWQ9aWQsIGNhbXBlb25lcykNCmNhbXBlb25lc1ssIGMoMSldIDwtIHNhcHBseShjYW1wZW9uZXNbLCBjKDEpXSwgYXMubnVtZXJpYykNCg0KDQoNCg0KbGFiZWxfY2FtcGVvbmVzIDwtIGNhbXBlb25lcw0KbnVtYmVyX29mX2JhciA8LSBucm93KGxhYmVsX2NhbXBlb25lcykNCg0KYW5nbGUgPC0gOTAgLSAzNjAgKiAobGFiZWxfY2FtcGVvbmVzJGlkLTAuNSkgL251bWJlcl9vZl9iYXIgICAgICMgSSBzdWJzdHJhY3QgMC41IGJlY2F1c2UgdGhlIGxldHRlciBtdXN0IGhhdmUgdGhlIGFuZ2xlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGJhcnMuIE5vdCBleHRyZW1lIHJpZ2h0KDEpIG9yIGV4dHJlbWUgbGVmdCAoMCkNCmxhYmVsX2NhbXBlb25lcyRoanVzdCA8LSBpZmVsc2UoIGFuZ2xlIDwgLTkwLCAxLCAwKQ0KbGFiZWxfY2FtcGVvbmVzJGFuZ2xlIDwtIGlmZWxzZShhbmdsZSA8IC05MCwgYW5nbGUrMTgwLCBhbmdsZSkNCg0KDQoNCmJhc2VfY2FtcGVvbmVzIDwtIGNhbXBlb25lcyAlPiUgDQogIGdyb3VwX2J5KG5hdGlvbmFsaXR5LngpICU+JSANCiAgc3VtbWFyaXNlKHN0YXJ0PW1pbihpZCksIGVuZD1tYXgoaWQpKSAlPiUgDQogIHJvd3dpc2UoKSAlPiUgDQogIG11dGF0ZSh0aXRsZT1tZWFuKGMoc3RhcnQsIGVuZCkpKQ0KDQpncmlkX2NhbXBlb25lcyA8LSBiYXNlX2NhbXBlb25lcw0KZ3JpZF9jYW1wZW9uZXMkZW5kIDwtIGdyaWRfY2FtcGVvbmVzJGVuZFsgYyggbnJvdyhncmlkX2NhbXBlb25lcyksIDE6bnJvdyhncmlkX2NhbXBlb25lcyktMSldICsgMQ0KZ3JpZF9jYW1wZW9uZXMkc3RhcnQgPC0gZ3JpZF9jYW1wZW9uZXMkc3RhcnQgLSAxDQpncmlkX2NhbXBlb25lcyA8LSBncmlkX2NhbXBlb25lc1stMSxdDQoNCnAgPC0gZ2dwbG90KGNhbXBlb25lcywgYWVzKHg9YXMuZmFjdG9yKHllYXIpLCB5PXRvdGFsX2NhbXBlb25hdG9zLCBmaWxsPW5hdGlvbmFsaXR5LngsIGNvbG9yID0gbmF0aW9uYWxpdHkueCkpICsgZ2VvbV9iYXIoYWVzKHg9YXMuZmFjdG9yKGlkKSwgeT10b3RhbF9jYW1wZW9uYXRvcywgZmlsbD1uYXRpb25hbGl0eS54KSwgc3RhdD0iaWRlbnRpdHkiLCBhbHBoYT0wLjUpICsNCiAgDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDAsIHkgPSA4LCB4ZW5kID0gMzIsIHllbmQgPSA4KSwgY29sb3VyID0gImdyZXkiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDAsIHkgPSA2LCB4ZW5kID0gMzIsIHllbmQgPSA2KSwgY29sb3VyID0gImdyZXkiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDAsIHkgPSA0LCB4ZW5kID0gMzIsIHllbmQgPSA0KSwgY29sb3VyID0gImdyZXkiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDAsIHkgPSAyLCB4ZW5kID0gMzIsIHllbmQgPSAyKSwgY29sb3VyID0gImdyZXkiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIA0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSByZXAobWF4KGNhbXBlb25lcyRpZCksNCksIHkgPSBjKDIsIDQsIDYsIDgpLCBsYWJlbCA9IGMoIjIiLCAiNCIsICI2IiwgIjgiKSAsIGNvbG9yPSJ3aGl0ZSIsIHNpemU9MyAsIGFuZ2xlPTAsIGZvbnRmYWNlPSJib2xkIiwgaGp1c3Q9MSkgKw0KICANCiAgIGdlb21fYmFyKGFlcyh4PWFzLmZhY3RvcihpZCksIHk9dG90YWxfY2FtcGVvbmF0b3MsIGZpbGw9bmF0aW9uYWxpdHkueCksIHN0YXQ9ImlkZW50aXR5IiwgYWxwaGE9MC41KSArDQogIHlsaW0oLTEwLDIxKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBsb3QubWFyZ2luID0gdW5pdChyZXAoLTEsNCksICJjbSIpICkgKw0KICBjb29yZF9wb2xhcigpICsgDQogIGdlb21fdGV4dChkYXRhPWxhYmVsX2NhbXBlb25lcywgYWVzKHg9aWQsIHk9MTAsIGxhYmVsPWRyaXZlclJlZiwgaGp1c3Q9aGp1c3QpLCBjb2xvcj0id2hpdGUiLCBmb250ZmFjZT0iYm9sZCIsYWxwaGE9MC42LCBzaXplPTMuNSwgYW5nbGU9IGxhYmVsX2NhbXBlb25lcyRhbmdsZSwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCg0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAwLjcwLCB5ID0gLTEsIHhlbmQgPSAyLjQ1LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSAgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAyLjYsIHkgPSAtMSwgeGVuZCA9IDMuNTUsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMy42NSwgeSA9IC0xLCB4ZW5kID0gNS40NSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSA1LjU1LCB5ID0gLTEsIHhlbmQgPSA3LjM1LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDcuNSwgeSA9IC0xLCB4ZW5kID0gMTAuNTAsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMTAuNywgeSA9IC0xLCB4ZW5kID0gMTkuMjAsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMTkuNCwgeSA9IC0xLCB4ZW5kID0gMjAuMywgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAyMC40NSwgeSA9IC0xLCB4ZW5kID0gMjMuNCwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKyANCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMjMuNjUsIHkgPSAtMSwgeGVuZCA9IDI0LjM1LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArIA0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAyNC42MCwgeSA9IC0xLCB4ZW5kID0gMjcsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMjcuMiwgeSA9IC0xLCB4ZW5kID0gMjkuNSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAyOS43LCB5ID0gLTEsIHhlbmQgPSAzMC41LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArIA0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAzMC43LCB5ID0gLTEsIHhlbmQgPSAzMS41LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDMxLjcsIHkgPSAtMSwgeGVuZCA9IDMyLjUsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMzIuNywgeSA9IC0xLCB4ZW5kID0gMzMuNSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKyB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoIGNvbG91ciA9ICJ3aGl0ZSIpLCANCiAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiLCBjb2xvdXIgPSAiZ3JheTEzIiksDQogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIgLCBjb2xvdXIgPSAiZ3JheTEzIiksDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIiAsIGNvbG91ciA9ICJncmF5MTMiKSkNCiAgDQoNCg0KcA0KICAgDQoNCmBgYA0KDQoNCiMgdGVtcGxvcyB5IHRpZW1wb3MgKHRlbXAgMjAyMSkgZ2xvYm8gaW50ZXJhY3Rpdm8NCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCmNhcnJlcmFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yYWNlcy5jc3YiKQ0KY2lyY3VpdG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9jaXJjdWl0cy5jc3YiKQ0KDQpjYXJyZXJhc18yMSA8LSBmdWxsX2pvaW4oY2FycmVyYXMsY2lyY3VpdG9zLCBjKCJjaXJjdWl0SWQiID0gImNpcmN1aXRJZCIpKSAlPiUNCiAgZmlsdGVyKHllYXI9PSIyMDIwIikgJT4lDQogIHNlbGVjdChyb3VuZCwgbmFtZS54LCBuYW1lLnksIGRhdGUsIGxvY2F0aW9uLGNvdW50cnksIGxhdCwgbG5nLCBhbHQpICU+JQ0KICBhcnJhbmdlKHJvdW5kKSAlPiUgDQogIG11dGF0ZShyb3VuZDIgPSByb3VuZCkgDQoNCmNhcnJlcmFzXzIxX3YyIDwtIGNhcnJlcmFzXzIxWywgYygxLCA0LCAxMCwgMiwgMywgNSwgNiwgNywgOCwgOSldDQpjYXJyZXJhc18yMV92MiA8LSBjYXJyZXJhc18yMV92MiU+JSAgdW5pdGUoLiAsdmFyaWFibGVzLCBjKDEsIDUsIDcpLCBzZXAgPSAiOyAiKQ0KDQojcHJ1ZWJhcyBwYXJhIG1hcGFzLCBubyBlamVjdXRhciBkZSBtb21lbnRvDQojbGlicmFyeSh3aWRnZXRmcmFtZSkNCiNsaWJyYXJ5KGxlYWZsZXQpDQojbCA8LSBsZWFmbGV0KCkgJT4lIHNldFZpZXcobGF0ID0gNDUuNjE1NjAsIGxuZyA9IDkuMjgxMTEwLCB6b29tPTEpDQojZnJhbWVXaWRnZXQobCkgDQoNCiNtYXBhQ2l1ZGFkeVB1ZWJsb21heW9yaW5jaUFjdSA8LSBsZWFmbGV0KCkgJT4lDQogIyBzZXRWaWV3KGxuZyA9IC0wLjI0MzU5MSwgbGF0ID0gMzguODIxLCB6b29tID0gNykgJT4lIA0KICAjYWRkTWFya2VycyhsbmcgPSAtMC4yNDM1OTEsIGxhdCA9IDM4LjgyMSAsIHBvcHVwID0gIlZhbGwgZGUgR2FsbGluZXJhIiklPiUNCiAgI3NldFZpZXcobG5nID0gLTAuNDE4NTk4LCBsYXQgPSA0MC4yMDExLCB6b29tID0gNykgJT4lIA0KICAjYWRkTWFya2VycyhsbmcgPSAtMC40MTg1OTgsIGxhdCA9IDQwLjIwMTEgLCBwb3B1cCA9ICJWaWxsYWhlcm1vc2EgZGVsIHJpbyIpICU+JSBhZGRUaWxlcygpDQojbWFwYUNpdWRhZHlQdWVibG9tYXlvcmluY2lBY3UNCg0KI01BUEEgREVMIE1VTkRPIERFIExBIE9TVElBIE5PIFRPQ0FSLCBwb25nbyBjb21vIGNvbWVudGFyaW8gcGFyYSBxdWUgbm8gdGFyZGUgdGFudG8gYWwga25pdGVhcg0KDQoNCmdsb2JvX2NpcmMgPC1jcmVhdGVfZ2xvYmUoKSAlPiUgZ2xvYmVfcG92KDQ1LjYxNTYwLCA5LjI4MTExMCkgJT4lIGdsb2JlX2JhcnMoY29vcmRzKGxhdCwgbG5nLCBsYWJlbCAgPSB2YXJpYWJsZXMsIGNvbG9yID0gcm91bmQyKSwgZGF0YSA9IGNhcnJlcmFzXzIxX3YyKSAgJT4lIHNjYWxlX2JhcnNfY29sb3IoKQ0KI2dsb2JvX2NpcmMNCg0Kb2JqZXRvc19ub19ib3JyYXIgPC0gYygidmljdG9yaWFzX2Nvbl9ub21icmUiLCAibl9jYXJyZXJhc19ub20iLCAibWFzX3ZpY3RvcmlhcyIpDQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIG9iamV0b3Nfbm9fYm9ycmFyXSkNCmBgYA0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KY2lyY3VpdG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9jaXJjdWl0cy5jc3YiKQ0KdGllbXBvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvbGFwX3RpbWVzLmNzdiIpDQpjYXJyZXJhcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmFjZXMuY3N2IikNCnBpbG90b3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2RyaXZlcnMuY3N2IikNCg0KY2lyY3VpdG9zX2dwIDwtIGZ1bGxfam9pbihjYXJyZXJhcywgY2lyY3VpdG9zLCBjKCJjaXJjdWl0SWQiID0gImNpcmN1aXRJZCIpKSAjYXNvY2lvIGxhcyBjYXJyZXJhcyBhIHN1IGNpcmN1aXRvDQp0aWVtcG9zdnVlbHRhX3hfY2FycmVyYSA8LSBmdWxsX2pvaW4oY2lyY3VpdG9zX2dwLCB0aWVtcG9zLCBjICgicmFjZUlkIiA9ICJyYWNlSWQiKSkgI3RpZW1wbyBkZSBsYXMgdnVlbHRhcyBwb3IgY2FkYSBjYXJyZXJhDQoNCnRpZW1wb3N2dWVsdGFfeF9jYXJyZXJhIDwtIGZ1bGxfam9pbih0aWVtcG9zdnVlbHRhX3hfY2FycmVyYSwgcGlsb3RvcywgYyAoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgIHNlbGVjdChjaXJjdWl0SWQsIG5hbWUueSwgZHJpdmVySWQsIGRyaXZlclJlZiwgdGltZS55LCBsYXAscG9zaXRpb24sIHllYXIsIGNvdW50cnkpICNmdXNpb25vIGNvbiBlbCBkZiBkZSBwaWxvdG9zIHBhcmEgYXNvY2lhciBjYWRhIHZ1ZWx0YSBhbCBub21icmUgZGVsIHBpbG90byBxdWUgbGEgaGl6bw0KDQoNCiNjYWxjdWxvIGVsIHJlY29yZCBkZSBjYWRhIGNpcmN1aXRvLCBmaWx0cmFuZG8gZWwgbWluaW1vIGRlIGxvcyB0aWVtcG9zIGVuIGNhZGEgY2lyY3VpdG8NCnJlY29yZF9kZV9jaXJjdWl0byA8LSB0aWVtcG9zdnVlbHRhX3hfY2FycmVyYSAlPiUgZ3JvdXBfYnkobmFtZS55KSAlPiUgc2xpY2VfbWluKHRpbWUueSwgbj0xKQ0KDQojbnVtZXJvIGRlIHJlY29yZHMgZGUgY2lyY3VpdG8gcXVlIHRpZW5lIGNhZGEgcGlsb3RvDQpyZWNvcmRfeF9waWxvdG8gPC0gcmVjb3JkX2RlX2NpcmN1aXRvICU+JSBncm91cF9ieShkcml2ZXJJZCkgJT4lIG11dGF0ZShudW1lcm9fcmVjb3JkcyA9IHN1bShuKCkpKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG51bWVyb19yZWNvcmRzKSAlPiUgZGlzdGluY3QoZHJpdmVyUmVmLCBudW1lcm9fcmVjb3JkcykgJT4lIGFycmFuZ2UoZGVzYyhudW1lcm9fcmVjb3JkcykpDQoNCg0KIyBtZXRlciBtYXBhIGRlbCBtdW5kbyBjb24gbGEgdWJpY2FjaW9uIGRlIGxvcyBjaXJjdWl0b3MgZW4gbGEgdGVtcG9yYWRhIDIwMjENCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0Kb2JqZXRvc19ub19ib3JyYXIgPC0gYygidmljdG9yaWFzX2Nvbl9ub21icmUiLCAibl9jYXJyZXJhc19ub20iLCAibWFzX3ZpY3RvcmlhcyIpDQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIG9iamV0b3Nfbm9fYm9ycmFyXSkNCg0KYGBgDQoNCiMgQ2Fww610dWxvIG9zY3VybyBkZWwgZGVwb3J0ZQ0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQojY3JlbyBkZiBkZSBtdWVydGVzIGRlIGZvcm11bGEgMQ0KbXVlcnRlc2YxIDwtIGRhdGEuZnJhbWUoDQogICJvcmRlbiIgPSAxOjQyLA0KICAiZHJpdmVyUmVmIiA9IGMoIkNoZXQgTWlsbGVyIiwgIkNhcmwgU2NhcmFib3JvdWdoIiwgIk9ub2ZyZSBNYXJpbW9uIiwgIk1hbm55IEF5dWxvIiwgIkJpbGwgVnVrb3ZpY2giLCAiQWxiZXJ0byBBc2NhcmkiLCJFdWdlbmlvIENhc3RlbGxvdHRpIiwgIktlaXRoIEFuZHJld3MiLCAiUGF0IE8nQ29ubm9yIiwgIkx1aWdpIE11c3NvIiwgIlBldGVyIENvbGxpbnMiLCAiU3R1YXJ0IExld2lzLUV2YW5zIiwgIkplcnJ5IFVuc2VyIiwgIkJvYiBDb3J0bmVyIiwgIkl2b3IgQnVlYiIsICJDaHJpcyBCcmlzdG93IiwgIkFsYW4gU3RhY2V5IiwgIkdpdWxpbyBDYWJpYW5jYSIsICJXb2xmZ2FuZyB2b24gVHJpcHMiLCAiQ2FyZWwgR29kaW4gZGUgQmVhdWZvcnQiLCAiSm9obiBUYXlsb3IiLCAiTG9yZW56byBCYW5kaW5pIiwgIkJvYiBBbmRlcnNvbiIsICJKbyBTY2hsZXNzZXIiLCAiR2VyaGFyZCBNaXR0ZXIiLCAiUGllcnMgQ291cmFnZSIsICJKb2NoZW4gUmluZHQiLCAiSm8gU2lmZmVydCIsICJSb2dlciBXaWxsaWFtc29uIiwgIkZyYW7Dp29pcyBDZXZlcnQiLCAiUGV0ZXIgUmV2c29uIiwgIkhlbG11dGggS29pbmlnZyIsICJNYXJrIERvbm9odWUiLCAiVG9tIFByeWNlIiwgIlJvbm5pZSBQZXRlcnNvbiIsICJQYXRyaWNrIERlcGFpbGxlciIsICJHaWxsZXMgVmlsbGVuZXV2ZSIsICJSaWNjYXJkbyBQYWxldHRpIiwgIkVsaW8gZGUgQW5nZWxpcyIsICJSb2xhbmQgUmF0emVuYmVyZ2VyIiwgIkF5cnRvbiBTZW5uYSIsICJKdWxlcyBCaWFuY2hpIiksDQogICJuYXRpb25hbGl0eSIgPSBjKCJBbWVyaWNhbiIsICJBbWVyaWNhbiIsICJBcmdlbnRpbmUiLCAiQW1lcmljYW4iLCAiQW1lcmljYW4iLCAiSXRhbGlhbiIsIkl0YWxpYW4iLCAiQW1lcmljYW4iLCAiQW1lcmljYW4iLCAiSXRhbGlhbiIsICJCcml0aXNoIiwgIkJyaXRpc2giLCAiQW1lcmljYW4iLCAiQW1lcmljYW4iLCAiQnJpdGlzaCIsICJCcml0aXNoIiwgIkJyaXRpc2giLCAiSXRhbGlhbiIsICJHZXJtYW4iLCAiRHV0Y2giLCAiQnJpdGlzaCIsICJJdGFsaWFuIiAsICJCcml0aXNoIiwgIkZyZW5jaCIsICJHZXJtYW4iLCAiQnJpdGlzaCIsICJBdXN0cmlhbiIsICJTd2lzcyIsICJCcml0aXNoIiwgIkZyZW5jaCIsICJBbWVyaWNhbiIsICJBdXN0cmlhbiIsICJBbWVyaWNhbiIsICJCcml0aXNoIiwgIlN3ZWRpc2giLCAiRnJlbmNoIiwgIkNhbmFkaWFuIiwgIkl0YWxpYW4iLCAiSXRhbGlhbiIsICJBdXN0cmlhbiIsICJCcmF6aWxpYW4iLCAiRnJlbmNoIiksDQogICJmZWNoYV9tdWVydGUiID0gYygxOTUzLCAxOTUzLCAxOTU0LCAxOTU1LCAxOTU1LCAxOTU1LCAxOTU3LCAxOTU3LCAxOTU4LDE5NTgsMTk1OCwxOTU4LDE5NTksMTk1OSwxOTU5LDE5NjAsIDE5NjAsMTk2MSwxOTYxLDE5NjQsMTk2NiwgMTk2NywgMTk2NywxOTY4LDE5NjksIDE5NzAsMTk3MCwxOTcxLDE5NzMsMTk3MywxOTc0LDE5NzQsMTk3NSwxOTc3LDE5NzgsMTk4MCwxOTgyLDE5ODIsMTk4NiwxOTk0LDE5OTQsMjAxNCkpDQojbm8gcG9uZ28gbGFzIGNvbWlsbGFzIGVuIGxvcyBhw7FvcyBwYXJhIHF1ZSBzZSBjcmVlbiBkaXJlY3RhbWVudGUgY29tbyBvYnNlcnZhY2lvbmVzIG51bWVyaWNhcw0KDQojY3JlbyB1biBkZiBjb24gdG9kb3MgbG9zIGHDsW9zIHBhcmEgbHVlZ28gZnVzaW9uYXJsbywgeWEgcXVlIG5vIGhheSBtdWVydGVzIHRvZG9zIGxvcyBhw7FvcyANCmFueW9zIDwtIGRhdGEuZnJhbWUoDQogICJvcmRlbiIgPSAxOjcxLA0KICAiYcOxbyIgPSBjKDE5NTA6MjAyMCkpDQoNCiNzdW1hdG9yaW8gZGUgbGFzIG11ZXJ0ZXMgcG9yIGHDsW8NCm11ZXJ0ZXNfYW55byA8LSBtdWVydGVzZjEgJT4lIGdyb3VwX2J5KGZlY2hhX211ZXJ0ZSkgJT4lIG11dGF0ZShtdWVydGVzeGFueW8gPSBzdW0obigpKSkgJT4lIGRpc3RpbmN0KGZlY2hhX211ZXJ0ZSwgbXVlcnRlc3hhbnlvKSANCg0KI2Z1c2lvbm8gbG9zIDIgZGZzIHBhcmEgcXVlIHRlbmdhIGVuIGN1ZW50YSBsb3MgYcOxb3MgZG9uZGUgbm8gaGF5IG11ZXJ0ZXMNCm11ZXJ0ZXNmMV9maW5hbCA8LSBmdWxsX2pvaW4obXVlcnRlc19hbnlvLCBhbnlvcywgYygiZmVjaGFfbXVlcnRlIiA9ICJhw7FvIikpICU+JSBzZWxlY3QoZmVjaGFfbXVlcnRlLG11ZXJ0ZXN4YW55bykgJT4lIGFycmFuZ2UoZmVjaGFfbXVlcnRlKQ0KDQojY29udmllcnRvIGxvcyBOL0EgZW4gMCwgZXMgZGVjaXIsIGN1YW5kbyBubyBoYXkgb2JzZXJ2YWNpb25lcywgaGEgaGFiaWRvIDAgbXVlcnRlcw0KbXVlcnRlc2YxX2ZpbmFsW2lzLm5hKG11ZXJ0ZXNmMV9maW5hbCldIDwtIDANCg0KI2dyYWZpY28gZGUgbGFzIG11ZXJ0ZXMgcG9yIGNhZGEgYcOxbyArIGxhIHRlbmRlbmNpYSBuZWdhdGl2YSBlYSBsbyBsYXJnbyBkZSBsYSBoaXN0b3JpYQ0KZ2dfbXVlcnRlcyA8LSBnZ3Bsb3QobXVlcnRlc2YxX2ZpbmFsLCBhZXMoeCA9IGZlY2hhX211ZXJ0ZSwgeSA9IG11ZXJ0ZXN4YW55byApKSArICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJ3aGl0ZSIpICsgZ2VvbV9zbW9vdGgoY29sb3VyID0gImN5YW4iLCBzZSA9IEZBTFNFKSArIGxhYnMoeCA9ICJBw7FvIiAsIHkgPSAiTsO6bWVybyBkZSBtdWVydGVzIikgICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIndoaXRlIiksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTEzIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTEzIiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIiksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEyIiwNCiAgICAgICAgY29sb3VyID0gIndoaXRlIiksIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpKSArbGFicyhjb2xvdXIgPSAid2hpdGUiKSArIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXkzOCIsDQogICAgbGluZXR5cGUgPSAiZG90dGVkIiksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gTkEpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1LA0KICAgICAgICBoanVzdCA9IDAuNSkpICtsYWJzKHRpdGxlID0gIkFjY2lkZW50ZXMgbW9ydGFsZXMgcG9yIGHDsW8iKSArIGdlb21fdGV4dChkYXRhID0gZGF0YS5mcmFtZSh4ID0gMjAwNC4xMDUyMjY0Mjg3NSwgeSA9IDAuMjM3NDUwNTE2OTQyMjQxLCANCiAgICBsYWJlbCA9ICJUZW5kZW5jaWEgbmVnYXRpdmEiKSwgbWFwcGluZyA9IGFlcyh4ID0geCwgeSA9IHksIA0KICAgIGxhYmVsID0gbGFiZWwpLCBjb2xvdXIgPSAiY3lhbiIsIGluaGVyaXQuYWVzID0gRkFMU0UsIHNpemUgPSAzKQ0KDQpnZ3Bsb3RseShnZ19tdWVydGVzKQ0KDQoNCg0KYGBgDQoNCiMgWzEuIEludHJvZHVjY2nDs25dey52ZXJkZWNpdG99DQoNClRlbmVtb3MgcGVuc2FkbyBlbGFib3JhciBlbCB0cmFiYWpvIGVuIGVxdWlwbyBzb2JyZSBGb3JtdWxhIDEsIHVuYSBjb21wZXRpY2nDs24gZGUgbGEgcXVlIHNvbW9zIG11eSBhZmljaW9uYWRvcywgZW50cmUgb3RyYXMgY29zYXMgcG9yIGxhIGltcG9ydGFuY2lhIHF1ZSB0aWVuZW4gbG9zIGRhdG9zIGEgbGEgaG9yYSBkZSBmb3JtYWxpemFyIGxhcyBlc3RyYXRlZ2lhcyBlbiBsYSBjb21wZXRpY2nDs24uIA0KDQoNCiMgUmVtYW5kbyBhIGNvbnRyYWNvcnJpZW50ZQ0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KI21hcyBwb3NpY2lvbmVzIHJlbW9udGFkYXMgZW4gdW5hIGNhcnJlcmEgZ3JhbiBwcmVtaW8NCg0KdGllbXBvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvbGFwX3RpbWVzLmNzdiIpDQpjYXJyZXJhcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmFjZXMuY3N2IikNCnJlc3VsdGFkb3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3Jlc3VsdHMuY3N2IikNCmNpcmN1aXRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvY2lyY3VpdHMuY3N2IikNCnBpbG90b3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2RyaXZlcnMuY3N2IikNCg0KcmVzdWx0YWRvc1ssIGMoNiw5KV0gPC0gc2FwcGx5KHJlc3VsdGFkb3NbLCBjKDYsOSldLCBhcy5udW1lcmljKSAjdHJhbnNmb3JtbyB2YXJpYWJsZXMgZ3JpZCB5IHBvc2l0aW9uT3JkZXIgZW4gbnVtZXJpY28NCnN0cihyZXN1bHRhZG9zKSAjIHBhcmEgY29tcHJvYmFybG8NCg0KDQojbWF5b3JlcyByZW1vbnRhZGFzIGRlIGxhIGhpc3RvcmlhLCBzZSByZXN0YSBwb3NpY2lvbiBkZSBzYWxpZGEgLSBwb3NpY2lvbiBmaW5hbA0KcHVlc3Rvc19yZW1vbnRhZG9zIDwtIHJlc3VsdGFkb3MgJT4lIG11dGF0ZShyZW1vbnRhZG9zID0gZ3JpZCAtIHBvc2l0aW9uT3JkZXIpICU+JSBzZWxlY3QocmFjZUlkLCBkcml2ZXJJZCwgZ3JpZCwgcG9zaXRpb25PcmRlciwgcmVtb250YWRvcykgDQoNCg0KI2RlIHRvZGEgbGEgaGlzdG9yaWENCmNpcmN1aXRvc19ncCA8LSBmdWxsX2pvaW4oY2FycmVyYXMsIGNpcmN1aXRvcywgYygiY2lyY3VpdElkIiA9ICJjaXJjdWl0SWQiKSkgJT4lIHNlbGVjdChjaXJjdWl0SWQsIG5hbWUueSwgcmFjZUlkLCB5ZWFyKQ0KDQpwdG9zX3JlbW9udF9jYXJyZXJhIDwtIGlubmVyX2pvaW4ocHVlc3Rvc19yZW1vbnRhZG9zLCBjaXJjdWl0b3NfZ3ApDQoNCnB1ZXN0b3NfcmVtb250X3BpbG90byA8LSBmdWxsX2pvaW4ocGlsb3RvcywgcHRvc19yZW1vbnRfY2FycmVyYSwgYygiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzbGljZV9tYXgocmVtb250YWRvcywgbj0xMCkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLG5hbWUueSx5ZWFyLCByYWNlSWQsIGdyaWQsIHBvc2l0aW9uT3JkZXIsIHJlbW9udGFkb3MpDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KDQojIGRlIGxhIGhpc290b3JpYSByZWNpZW50ZQ0KY2lyY3VpdG9zX2dwX3JlY2llbnQgPC0gZnVsbF9qb2luKGNhcnJlcmFzLCBjaXJjdWl0b3MsIGMoImNpcmN1aXRJZCIgPSAiY2lyY3VpdElkIikpICU+JSBzZWxlY3QoY2lyY3VpdElkLCBuYW1lLnksIHJhY2VJZCwgeWVhcikgJT4lIGZpbHRlcih5ZWFyID49IDE5OTUpDQoNCnB0b3NfcmVtb250X2NhcnJlcmFfcmVjaWVudCA8LSBpbm5lcl9qb2luKHB1ZXN0b3NfcmVtb250YWRvcywgY2lyY3VpdG9zX2dwX3JlY2llbnQpDQoNCnB1ZXN0b3NfcmVtb250X3BpbG90b19yZWNpZW50IDwtIGZ1bGxfam9pbihwaWxvdG9zLCBwdG9zX3JlbW9udF9jYXJyZXJhX3JlY2llbnQsIGMoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgc2xpY2VfbWF4KHJlbW9udGFkb3MsIG49MTApICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgbmFtZS55LCB5ZWFyLHJhY2VJZCwgZ3JpZCwgcG9zaXRpb25PcmRlciwgcmVtb250YWRvcykgJT4lIHNsaWNlKDE6NCw2OjgsMTApICU+JSBhcnJhbmdlKGRlc2MocmVtb250YWRvcykpDQoNCmdncmVtb250YWRvcyA8LSBnZ3Bsb3QocHVlc3Rvc19yZW1vbnRfcGlsb3RvX3JlY2llbnQsIGFlcyh4ID0gcmVvcmRlcihkcml2ZXJSZWYsIHJlbW9udGFkb3MpLCByZW1vbnRhZG9zKSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkgKyBsYWJzKHggPSAiUGlsb3RvcyIsIHkgPSAiTsK6IGRlIHB1ZXN0b3MgcmVtb250YWRvcyIgKQ0KZ2dyZW1vbnRhZG9zDQoNCm9iamV0b3Nfbm9fYm9ycmFyIDwtIGMoInZpY3Rvcmlhc19jb25fbm9tYnJlIiwgIm5fY2FycmVyYXNfbm9tIiwgIm1hc192aWN0b3JpYXMiKQ0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBvYmpldG9zX25vX2JvcnJhcl0pDQpgYGANCg0KDQojIEFMT05TTyB2cyBIQU1JTFRPTg0KDQpgYGB7ciwgZXZhbD1UUlVFLCBlY2hvPVRSVUV9DQoNCiNzZSBuZWNlc2l0YSB0ZW5lciBjYXJnYWRvICJuX2NhcnJlcmFzX25vbSIsICJ2aWN0b3JpYXNfY29uX25vbWJyZSINCiMxMjM0DQpmb3Rvc19BTE9fdnNfSEFNIDwtIGMoIi4vaW1hZ2VuZXMvcGlsb3Rvcy9hbG9uc28ucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9oYW1pbHRvbi5wbmciKQ0KZm90b3NfZXNwX2luZyA8LSBjKCIuL2ltYWdlbmVzL3BhaXNlcy9lc3BhbnlhLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy91ay5wbmciKQ0Kbl9jYXJyZXJhc19hbG9faGFtIDwtIG5fY2FycmVyYXNfbm9tICU+JSBmaWx0ZXIoZHJpdmVyUmVmICVpbiUgYygiYWxvbnNvIiwgImhhbWlsdG9uIikpDQoNCm5fdmljdG9yaWFzX2Fsb19oYW0gPC0gdmljdG9yaWFzX2Nvbl9ub21icmUgJT4lIGZpbHRlcihkcml2ZXJSZWYgJWluJSBjKCJhbG9uc28iLCAiaGFtaWx0b24iKSkNCg0KYWxvX3ZzX2hhbSA8LSBmdWxsX2pvaW4obl9jYXJyZXJhc19hbG9faGFtLCBuX3ZpY3Rvcmlhc19hbG9faGFtLCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIikpICU+JSBzZWxlY3QoIGRyaXZlclJlZiwgbnVtZXJvX2NhcnJlcmFzLCBuX3ZpY3RvcmlhcykgJT4lIGFkZF9jb2x1bW4oZm90b3NfZXNwX2luZywgZm90b3NfQUxPX3ZzX0hBTSkgDQoNCmxpYnJhcnkoZ3QpDQphbG9fdnNfaGFtX3RhYmxhIDwtIGFsb192c19oYW0gJT4lIGd0KCkgJT4lIHRleHRfdHJhbnNmb3JtKCBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKGZvdG9zX2VzcF9pbmcpKSwgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OmxvY2FsX2ltYWdlKHgsIGhlaWdodCA9IDUwKX0pICU+JSB0ZXh0X3RyYW5zZm9ybSggbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gYyhmb3Rvc19BTE9fdnNfSEFNKSksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojpsb2NhbF9pbWFnZSh4LCBoZWlnaHQgPSAxMDApfSkgJT4lIHRhYl9oZWFkZXIodGl0bGUgPSBtZCgiKipBbG9uc28gdnMgSGFtaWx0b24qKiIpLCBzdWJ0aXRsZSA9IG1kKCJDb21wYXJhY2nDs24iKSkgJT4lICAgY29sc19sYWJlbCgNCiAgICBkcml2ZXJSZWYgPSBodG1sKCIiKSwNCiAgICBudW1lcm9fY2FycmVyYXMgPSBodG1sKCJOwrogY2FycmVyYXMiKSwNCiAgICBuX3ZpY3RvcmlhcyA9IGh0bWwoIk7CuiB2aWN0b3JpYXMiKSwNCiAgICBmb3Rvc19lc3BfaW5nID0gaHRtbCgiUGHDrXMiKSwNCiAgICBmb3Rvc19BTE9fdnNfSEFNID0gaHRtbCgiIikpICU+JSAgDQogIHRhYl9vcHRpb25zKHRhYmxlLmJhY2tncm91bmQuY29sb3IgPSAiZ3JheTEzIiwgICB0YWJsZS5mb250LmNvbG9yLmxpZ2h0ID0gImN5YW4iKSAlPiUgDQogIGNvbHNfYWxpZ24oYWxpZ24gPSAiY2VudGVyIiwNCiAgY29sdW1ucyA9IGV2ZXJ5dGhpbmcoKSkNCg0KYWxvX3ZzX2hhbV90YWJsYQ0KYGBgDQoNCiMgQXVkaWVuY2lhcw0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KI2F1ZGllbmNpYXMNCg0KDQphdWRpZW5jaWFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9hdWRpZW5jaWFzRjEuY3N2IikNCg0KDQpnZ19hdWRpZW5jaWFzIDwtIGdncGxvdChhdWRpZW5jaWFzLCBhZXMoeD15ZWFyLCB5PSBudW1lcm9fZXNwZWN0YWRvcmVzKSkgKw0KICBnZW9tX3NlZ21lbnQoIGFlcyh4PXllYXIsIHhlbmQgPSB5ZWFyLCB5PTAsIHllbmQ9IG51bWVyb19lc3BlY3RhZG9yZXMgLCBzaXplID0gIjEiKSkgKw0KICBnZW9tX3BvaW50KCBzaXplPTUsIGNvbG9yPSJibHVlIiwgZmlsbD1hbHBoYSgiY3lhbiIsIDgpLCBhbHBoYT0wLjcsIHNoYXBlPTIxLCBzdHJva2U9MikgKyAgDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBicmVha3MgPSBzZXEoMjAwNCwgMjAyMCwgMSksDQogICAgbGltaXRzID0gYygyMDAzLCAyMDIxKSkgKyBsYWJzKHggPSAiQcOxbyIsIHkgPSAiTnVtZXJvIGRlIGVzcGVjdGFkb3JlcyIgKSAgKyB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIiksDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIikpICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXkyMCIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXkyMCIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJ3aGl0ZSIsDQogICAgICAgIGhqdXN0ID0gMC41KSkgK2xhYnModGl0bGUgPSAiRXZvbHVjacOzbiBkZSBsYSBhdWRpZW5jaWEiLA0KICAgIGNvbG91ciA9ICJ3aGl0ZSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDQpKSAjKyB0cmFuc2l0aW9uX3JldmVhbChudW1lcm9fZXNwZWN0YWRvcmVzKQ0KDQpnZ3Bsb3RseShnZ19hdWRpZW5jaWFzKQ0KDQoNCmBgYA0KDQojIFByZXN1cHVlc3Rvcw0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LmV4dHJhPSdhbmdsZT05MCcsIGVjaG8gPSBUUlVFfQ0KI3ByZXN1cHVlc3Rvcw0KDQpwcmVzdXB1ZXN0b3MgPC0gcmVhZF9leGNlbCgiZGF0b3MvcHJlc3VwdWVzdG9zLnhsc3giKQ0KDQpnZ19wcmVzdXAgPC0gZ2dwbG90KHByZXN1cHVlc3RvcywgYWVzKHllYXIsIFByZXN1cHVlc3RvLCBjb2xvciA9IEVzY3VkZXJpYSkpICsgDQogIGdlb21fcG9pbnQoKSArIGdlb21fbGluZSgpICsgDQogIGxhYnMoeCA9ICJBw7FvIiwgeSA9ICJQcmVzdXB1ZXN0byBlbiDigqwiICkgKw0KICAgIHNjYWxlX3hfY29udGludW91cygNCiAgICBicmVha3MgPSBzZXEoMjAxNSwgMjAyMywgMSksDQogICAgbGltaXRzID0gYygyMDE0LCAyMDI0KSkgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKCBicmVha3MgPSBzZXEoMCwgNzAwMDAwMDAwLCAxMDAwMDAwMDApLA0KICAgIGxpbWl0cyA9IGMoMCwgNjAwMDAwMDAwKSkgICsgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJ3aGl0ZSIsDQogICAgICAgIGxpbmV0eXBlID0gImJsYW5rIiksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIndoaXRlIiwNCiAgICAgICAgbGluZXR5cGUgPSAiYmxhbmsiKSwgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsDQogICAgICAgIGZhY2UgPSAiYm9sZCIsIGNvbG91ciA9ICJjeWFuIiwgdmp1c3QgPSAwLjc1KSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIiksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsDQogICAgICAgIGZhY2UgPSAiYm9sZCIsIGNvbG91ciA9ICJjeWFuIiwgaGp1c3QgPSAwLjUsDQogICAgICAgIHZqdXN0ID0gMC43NSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsDQogICAgICAgIGNvbG91ciA9ICJjeWFuIiksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsDQogICAgICAgIGZhY2UgPSAiYm9sZCIsIGNvbG91ciA9ICJjeWFuIiksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIsDQogICAgICAgIGNvbG91ciA9ICJ3aGl0ZSIpLCBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiKSwNCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIiksDQogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiKSkgK2xhYnModGl0bGUgPSAiUFJFU1VQVUVTVE8gREUgQ0FEQSBFUVVJUE8gUE9SIFRFTVBPUkFEQSIpICsgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSBOQSksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSBOQSksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIsDQogICAgICAgIGNvbG91ciA9IE5BKSwgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIiwNCiAgICAgICAgY29sb3VyID0gTkEpKSArIHRoZW1lKGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiKSwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTIwIiwNCiAgICBsaW5ldHlwZSA9ICJzb2xpZCIpLCBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5MTUiLA0KICAgIGxpbmV0eXBlID0gInNvbGlkIikpDQogDQpnZ3Bsb3RseShnZ19wcmVzdXApICNwYXJhIHF1ZSBzZWEgaW50ZXJhY3Rpdm8NCmBgYA0KDQoNCiMgbWFwYSBkZSBjb3JvcGxldGFzIGRlIHBpbG90b3MgcG9yIHBhaXMgKHBvciB0ZXJtaW5hcikNCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KDQpuYWNpb25hbGlkYWQgPC0gcGlsb3RvcyAlPiUgZ3JvdXBfYnkobmF0aW9uYWxpdHkpICU+JSANCiAgbXV0YXRlKG51bWVyb19jb21wYXRyaW90YXMgPSBzdW0obigpKSkgJT4lIA0KICBkaXN0aW5jdChudW1lcm9fY29tcGF0cmlvdGFzKSAlPiUgYXJyYW5nZShkZXNjKG51bWVyb19jb21wYXRyaW90YXMpKSAlPiUgDQogIG11dGF0ZShjb3VudHJ5ID0gY2FzZV93aGVuKG5hdGlvbmFsaXR5ID09ICJCcml0aXNoIiB+ICJVbml0ZWQgS2luZ2RvbSIsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkFtZXJpY2FuIiB+ICJVbml0ZWQgU3RhdGVzIiwNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiSXRhbGlhbiIgfiAnSXRhbHknLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJGcmVuY2giIH4gJ0ZyYW5jZScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkdlcm1hbiIgfiAnR2VybWFueScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkJyYXppbGlhbiIgfiAnQnJhemlsJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiQXJnZW50aW5lIiB+ICdBcmdlbnRpbmEnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJTd2lzcyIgfiAnU3dpdHplcmxhbmQnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJCZWxnaWFuIiB+ICdCZWxnaXVtJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiU291dGggQWZyaWNhbiIgfiAnU291dGggQWZyaWNhJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiSmFwYW5lc2UiIH4gJ0phcGFuJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiQXVzdHJhbGlhbiIgfiAnQXVzdHJhbGlhJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiRHV0Y2giIH4gJ05ldGhlcmxhbmRzJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiU3BhbmlzaCIgfiAnU3BhaW4nLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJBdXN0cmlhbiIgfiAnQXVzdHJpYScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkNhbmFkaWFuIiB+ICdDYW5hZGEnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJTd2VkaXNoIiB+ICdTd2VkZW4nLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJGaW5uaXNoIiB+ICdGaW5sYW5kJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiTmV3IFplYWxhbmRlciIgfiAnTmV3IFplYWxhbmQnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJNZXhpY2FuIiB+ICdNZXhpY28nLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJJcmlzaCIgfiAnSXJlbGFuZCcsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkRhbmlzaCIgfiAnRGVubWFyaycsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIlBvcnR1Z3Vlc2UiIH4gJ1BvcnR1Z2FsJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiTW9uZWdhc3F1ZSIgfiAnRnJhbmNlJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiUmhvZGVzaWFuIiB+ICdaaW1iYWJ3ZScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIlVydWd1YXlhbiIgfiAnVXJ1Z3VheScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIlJ1c3NpYW4iIH4gJ1J1c3NpYScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkNvbG9tYmlhbiIgfiAnQ29sb21iaWEnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJWZW5lenVlbGFuIiB+ICdWZW5lenVlbGEnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJFYXN0IEdlcm1hbiIgfiAnR2VybWFuJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiSW5kaWFuIiB+ICdJbmRpYScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIlRoYWkiIH4gJ1RoYWlsYW5kJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiUG9saXNoIiB+ICdQb2xhbmQnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJIdW5nYXJpYW4iIH4gJ0h1bmdhcnknLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJDemVjaCIgfiAnQ3plY2ggUmVwLicsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIk1hbGF5c2lhbiIgfiAnTWFsYXlzaWEnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJDaGlsZWFuIiB+ICdDaGlsZScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkxpZWNodGVuc3RlaW5lciIgfiAnU3dpdHplcmxhbmQnLA0KICAgICAgICAgIG5hdGlvbmFsaXR5ID09ICJBbWVyaWNhbi1JdGFsaWFuIiB+ICdVbml0ZWQgU3RhdGVzJywNCiAgICAgICAgICBuYXRpb25hbGl0eSA9PSAiQXJnZW50aW5lLUl0YWxpYW4iIH4gJ0FyZ2VudGluYScsDQogICAgICAgICAgbmF0aW9uYWxpdHkgPT0gIkluZG9uZXNpYW4iIH4gJ0luZG9uZXNpYScpKQ0KDQoNCmxpYnJhcnkodG1hcCkNCmRhdGEoV29ybGQpDQp3b3JsZCA8LSBXb3JsZDsgcm0oV29ybGQpDQpgYGANCg0KDQojIyAqKlRIRSBQTEFOKioNCg0KYGBge3IsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCmxpYnJhcnkobWVtZSkNCiNteV9mb3RvIDwtICJodHRwczovL2UwMC1lbG11bmRvLnVlY2RuLmVzL2Fzc2V0cy9tdWx0aW1lZGlhL2ltYWdlbmVzLzIwMTcvMDUvMTIvMTQ5NDU4OTkzNDYzMDYuanBnIg0KI21lbWUobXlfZm90bywgIk1VWSBUUkFOUVVJTE9TIiwgIlNFIFZJRU5FIFRSQUJBSkFaTyIsIHNpemUgPSAyICwgY29sb3IgPSAiYmx1ZSIsIHZqdXN0ID0gMS4wNSkNCg0KYGBgDQoNCiMgMi4gRGF0b3MNCg0KSGVtb3MgZW5jb250cmFkbyBlbiBba2FnZ2xlXShodHRwczovL3d3dy5rYWdnbGUuY29tLykgYmFzdGFudGVzIGNvbmp1bnRvcyBkZSBkYXRvcyBjb24gbG9zIHF1ZSBwb2RlciB0cmFiYWphciwgcGVybyBlc3BlY2lhbG1lbnRlIFtlc3RlXShodHRwczovL3d3dy5rYWdnbGUuY29tL3JvaGFucmFvL2Zvcm11bGEtMS13b3JsZC1jaGFtcGlvbnNoaXAtMTk1MC0yMDIwKSwgcXVlIHBvc2VlIGdyYW4gdmFyaWVkYWQgZGUgZGF0b3MgZW4gbG8gcmVmZXJlbnRlIGEgcGlsb3RvcywgcmVzdWx0YWRvcywgY2lyY3VpdG9zLCB0aWVtcG9zLCBldGMuLi4gQ29uc2lkZXJhbW9zIHF1ZSBwYXJhIGVtcGV6YXIgYSB0cmFiYWphciBzZXLDoSBzdWZpY2llbnRlLCB5IGVuIGZ1bmNpw7NuIGRlIGNvbW8gdmF5YW1vcyBkaXJpZ2llbmRvIGVsIHRyYWJham8sIGJ1c2NhcmVtb3MgZGlmZXJlbnRlcyBjb25qdW50byBkZSBkYXRvcyBjb24gbG9zIHF1ZSBhcG95YXJub3MuDQoNCiMgMy4gVHJhYmFqb3MgZW4gbG9zIHF1ZSBub3MgdmFtb3MgYSBiYXNhcg0KDQpDb24gbG9zIGRhdG9zIHF1ZSBoZW1vcyBlbmNvbnRyYWRvLCBleGlzdGVuIHVuYSBzZXJpZSBkZSBjw7NkaWdvcyBxdWUgeWEgdHJhYmFqYW4gY29uIGVzdG9zIGRhdG9zLCBlc3BlY2lhbG1lbnRlIFtlc3RlXShodHRwczovL3d3dy5rYWdnbGUuY29tL2VrcmVtYmF5YXIvZm9ybXVsYS0xLTcwdGgtYW5uaXZlcnNhcnkpLCBxdWUgaGEgY29uc2VndWlkbyByZWFsaXphciBhbsOhbGlzaXMgY29uIGVzdGUgY29uanVudG8gZGUgZGF0b3MgeSB2YXJpYXMgaWx1c3RyYWNpb25lcyBtdXkgbGxhbWF0aXZhcywgcG9yIGxvIHF1ZSBwb2RyZW1vcyB0b21hcmxvIGNvbW8gcmVmZXJlbmNpYSBkdXJhbnRlIGVsIGluaWNpbyBkZWwgdHJhYmFqbw0KDQo+ICJOYWRpZSBlcyBtw6FzIHLDoXBpZG8gcXVlIGVsIG5hbm8iDQoNCg0KDQpgYGB7cn0NCg0KbGlicmFyeShtYWdpY2spDQpjb2NoZTE5NTAgPC0gaW1hZ2VfcmVhZCgiLi9pbWFnZW5lcy9jb2NoZXMvMTk1MC5qcGciKSAlPiUgaW1hZ2Vfc2NhbGUoLiwgIjUwMCIpICU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5NTAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTYwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5NjAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5NjAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTcwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5NzAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5NzAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTgwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5ODAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5ODAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTkwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5OTAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5OTAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUyMDA1IDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzIwMDUuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjIwMDUiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUyMDIwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzIwMjAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjIwMjAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGVzIDwtIGMoY29jaGUxOTUwLCBjb2NoZTE5NjAsIGNvY2hlMTk3MCwgY29jaGUxOTgwLCBjb2NoZTE5OTAsIGNvY2hlMjAwNSwgY29jaGUyMDIwKQ0KDQppbWFnZV9hbmltYXRlKGltYWdlX3NjYWxlKGNvY2hlcyksIGZwcyA9IDAuNSkNCmBgYA0KDQo=